home *** CD-ROM | disk | FTP | other *** search
/ Gamers Delight 2 / Gamers Delight 2.iso / Aminet / game / role / pinfocom_3_0.lha / Source / amiga_console.c < prev    next >
C/C++ Source or Header  |  1992-10-22  |  89KB  |  4,342 lines

  1. /* amiga_console.c
  2.  *
  3.  *  ``pinfocom'' -- a portable Infocom Inc. data file interpreter.
  4.  *  Copyright (C) 1987-1992  InfoTaskForce
  5.  *
  6.  *  This program is free software; you can redistribute it and/or modify
  7.  *  it under the terms of the GNU General Public License as published by
  8.  *  the Free Software Foundation; either version 2 of the License, or
  9.  *  (at your option) any later version.
  10.  *
  11.  *  This program is distributed in the hope that it will be useful,
  12.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *  GNU General Public License for more details.
  15.  *
  16.  *  You should have received a copy of the GNU General Public License
  17.  *  along with this program; see the file COPYING.  If not, write to the
  18.  *  Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  */
  20.  
  21. /*
  22.  * $Header: RCS/amiga_console.c,v 3.0 1992/10/21 16:56:19 pds Stab $
  23.  */
  24.  
  25. #ifndef _AMIGA_GLOBAL_H
  26. #include "amiga_global.h"
  27. #endif    /* !_AMIGA_GLOBAL_H */
  28.  
  29.     /* ConCharWidth(const UBYTE Char):
  30.      *
  31.      *    Calculate the pixel width of a glyph.
  32.      */
  33.  
  34. UWORD
  35. ConCharWidth(const UBYTE Char)
  36. {
  37.     return((UWORD)TextLength(RPort,(STRPTR)&Char,1));
  38. }
  39.  
  40.     /* ConCursorOff():
  41.      *
  42.      *    Turn the terminal cursor on.
  43.      */
  44.  
  45. VOID
  46. ConCursorOff()
  47. {
  48.         /* Is it still enabled? */
  49.  
  50.     if(CursorEnabled)
  51.     {
  52.         LONG    Left    = LastCursorX + Window -> BorderLeft,
  53.             Top    = LastCursorY + Window -> BorderTop;
  54.  
  55.             /* Turn on xor operation. */
  56.  
  57.         SetDrMd(RPort,JAM1 | COMPLEMENT);
  58.  
  59.             /* Complement all planes. */
  60.  
  61.         SetAPen(RPort,(1 << Depth) - 1);
  62.  
  63.             /* Is the window inactive? */
  64.  
  65.         if(!WindowIsActive)
  66.         {
  67.                 /* Set the cross-hatch pattern. */
  68.  
  69.             SetAfPt(RPort,&ChipData[CHIPDATA_PATTERN],1);
  70.  
  71.                 /* Render the cursor data. */
  72.  
  73.             RectFill(RPort,Left,Top,Left + NewCursorWidth - 1,Top + TextFontHeight - 1);
  74.  
  75.                 /* Reset the pattern. */
  76.  
  77.             SetAfPt(RPort,NULL,0);
  78.         }
  79.         else
  80.             RectFill(RPort,Left,Top,Left + NewCursorWidth - 1,Top + TextFontHeight - 1);
  81.  
  82.             /* Reset the drawing mode. */
  83.  
  84.         SetDrMd(RPort,JAM2);
  85.  
  86.             /* Reset the drawing pen. */
  87.  
  88.         SetAPen(RPort,ConTextPen);
  89.  
  90.             /* It's turned off now. */
  91.  
  92.         CursorEnabled = FALSE;
  93.     }
  94. }
  95.  
  96.     /* ConCursorOn(const int New):
  97.      *
  98.      *    Turn the terminal cursor off.
  99.      */
  100.  
  101. VOID
  102. ConCursorOn(const int New)
  103. {
  104.         /* Is it still disabled? */
  105.  
  106.     if(!CursorEnabled)
  107.     {
  108.         LONG    Left    = CursorX + Window -> BorderLeft,
  109.             Top    = CursorY + Window -> BorderTop;
  110.  
  111.             /* Remember new cursor width. */
  112.  
  113.         switch(New)
  114.         {
  115.             case CURSOR_NOCHANGE:    break;
  116.  
  117.             case CURSOR_AVERAGE:    NewCursorWidth = DefaultCursorWidth;
  118.                         break;
  119.  
  120.             default:        NewCursorWidth = New;
  121.                         break;
  122.         }
  123.  
  124.             /* Turn on xor operation. */
  125.  
  126.         SetDrMd(RPort,JAM1 | COMPLEMENT);
  127.  
  128.             /* Complement all planes. */
  129.  
  130.         SetAPen(RPort,(1 << Depth) - 1);
  131.  
  132.             /* Is the window inactive? */
  133.  
  134.         if(!WindowIsActive)
  135.         {
  136.                 /* Set the cross-hatch pattern. */
  137.  
  138.             SetAfPt(RPort,&ChipData[CHIPDATA_PATTERN],1);
  139.  
  140.                 /* Render the cursor data. */
  141.  
  142.             RectFill(RPort,Left,Top,Left + NewCursorWidth - 1,Top + TextFontHeight - 1);
  143.  
  144.                 /* Reset the pattern. */
  145.  
  146.             SetAfPt(RPort,NULL,0);
  147.         }
  148.         else
  149.             RectFill(RPort,Left,Top,Left + NewCursorWidth - 1,Top + TextFontHeight - 1);
  150.  
  151.             /* Reset the drawing mode. */
  152.  
  153.         SetDrMd(RPort,JAM2);
  154.  
  155.             /* Reset the drawing pen. */
  156.  
  157.         SetAPen(RPort,ConTextPen);
  158.  
  159.             /* Remember cursor width. */
  160.  
  161.         OldCursorWidth = NewCursorWidth;
  162.  
  163.             /* It's turn on now. */
  164.  
  165.         CursorEnabled = TRUE;
  166.  
  167.             /* Remember cursor position. */
  168.  
  169.         LastCursorX = CursorX;
  170.         LastCursorY = CursorY;
  171.     }
  172. }
  173.  
  174.     /* ConMove(const int Delta,const int New):
  175.      *
  176.      *    Move the cursor.
  177.      */
  178.  
  179. VOID
  180. ConMove(const int Delta,const int New)
  181. {
  182.         /* If the cursor is still enabled, turn it
  183.          * off before repositioning it.
  184.          */
  185.  
  186.     if(CursorEnabled)
  187.     {
  188.             /* Turn the cursor off. */
  189.  
  190.         ConCursorOff();
  191.  
  192.             /* Move it. */
  193.  
  194.         CursorX += Delta;
  195.  
  196.             /* Turn the cursor back on. */
  197.  
  198.         ConCursorOn(New);
  199.     }
  200.     else
  201.     {
  202.         CursorX += Delta;
  203.  
  204.         switch(New)
  205.         {
  206.             case CURSOR_NOCHANGE:    NewCursorWidth = OldCursorWidth;
  207.                         break;
  208.  
  209.             case CURSOR_AVERAGE:    NewCursorWidth = OldCursorWidth = DefaultCursorWidth;
  210.                         break;
  211.  
  212.             default:        NewCursorWidth = OldCursorWidth = New;
  213.                         break;
  214.         }
  215.     }
  216. }
  217.  
  218.     /* ConSet(const int X,const int Y,const int New):
  219.      *
  220.      *    Place the cursor at a specific position.
  221.      */
  222.  
  223. VOID
  224. ConSet(const int X,const int Y,const int New)
  225. {
  226.         /* If the cursor is still enabled, turn it
  227.          * off before repositioning it.
  228.          */
  229.  
  230.     if(CursorEnabled)
  231.     {
  232.             /* Turn the cursor off. */
  233.  
  234.         ConCursorOff();
  235.  
  236.             /* Move drawing pen. */
  237.  
  238.         Move(RPort,X + Window -> BorderLeft,Y + ThisFont -> tf_Baseline + Window -> BorderTop);
  239.  
  240.             /* Position the cursor. */
  241.  
  242.         CursorX = X;
  243.         CursorY = Y;
  244.  
  245.             /* Turn the cursor back on. */
  246.  
  247.         ConCursorOn(New);
  248.     }
  249.     else
  250.     {
  251.             /* Remember new cursor width. */
  252.  
  253.         switch(New)
  254.         {
  255.             case CURSOR_NOCHANGE:    NewCursorWidth = OldCursorWidth;
  256.                         break;
  257.  
  258.             case CURSOR_AVERAGE:    NewCursorWidth = OldCursorWidth = DefaultCursorWidth;
  259.                         break;
  260.  
  261.             default:        NewCursorWidth = OldCursorWidth = New;
  262.                         break;
  263.         }
  264.  
  265.             /* Move drawing pen. */
  266.  
  267.         Move(RPort,X + Window -> BorderLeft,Y + ThisFont -> tf_Baseline + Window -> BorderTop);
  268.  
  269.             /* Position the cursor. */
  270.  
  271.         CursorX = X;
  272.         CursorY = Y;
  273.     }
  274. }
  275.  
  276.     /* ConClearEOL():
  277.      *
  278.      *    Clear to end of current line.
  279.      */
  280.  
  281. VOID
  282. ConClearEOL()
  283. {
  284.         /* Is there anything to clear? */
  285.  
  286.     if(CursorX < WindowWidth)
  287.     {
  288.             /* Turn the cursor off before the line is cleared. */
  289.  
  290.         if(CursorEnabled)
  291.         {
  292.                 /* Turn the cursor off. */
  293.  
  294.             ConCursorOff();
  295.  
  296.                 /* Clear the remaining line. */
  297.  
  298.             SetAPen(RPort,ConBackPen);
  299.             RectFill(RPort,CursorX + Window -> BorderLeft,CursorY + Window -> BorderTop,Window -> Width - (Window -> BorderRight + 1),CursorY + Window -> BorderTop + TextFontHeight - 1);
  300.             SetAPen(RPort,ConTextPen);
  301.  
  302.                 /* Turn the cursor back on. */
  303.  
  304.             ConCursorOn(CURSOR_NOCHANGE);
  305.         }
  306.         else
  307.         {
  308.             SetAPen(RPort,ConBackPen);
  309.             RectFill(RPort,CursorX + Window -> BorderLeft,CursorY + Window -> BorderTop,Window -> Width - (Window -> BorderRight + 1),CursorY + Window -> BorderTop + TextFontHeight - 1);
  310.             SetAPen(RPort,ConTextPen);
  311.         }
  312.     }
  313. }
  314.  
  315.     /* ConCharBackspace(const int Delta,const int New):
  316.      *
  317.      *    Move the cursor one glyph back.
  318.      */
  319.  
  320. VOID
  321. ConCharBackspace(const int Delta,const int New)
  322. {
  323.     RedrawInputLine = TRUE;
  324.  
  325.     CursorX -= Delta;
  326.  
  327.     switch(New)
  328.     {
  329.         case CURSOR_NOCHANGE:    NewCursorWidth = OldCursorWidth;
  330.                     break;
  331.  
  332.         case CURSOR_AVERAGE:    NewCursorWidth = OldCursorWidth = DefaultCursorWidth;
  333.                     break;
  334.  
  335.         default:        NewCursorWidth = OldCursorWidth = New;
  336.                     break;
  337.     }
  338. }
  339.  
  340.     /* ConCharDelete(const int New):
  341.      *
  342.      *    Delete the character under the cursor.
  343.      */
  344.  
  345. VOID
  346. ConCharDelete(const int New)
  347. {
  348.     RedrawInputLine = TRUE;
  349.  
  350.     switch(New)
  351.     {
  352.         case CURSOR_NOCHANGE:    NewCursorWidth = OldCursorWidth;
  353.                     break;
  354.  
  355.         case CURSOR_AVERAGE:    NewCursorWidth = OldCursorWidth = DefaultCursorWidth;
  356.                     break;
  357.  
  358.         default:        NewCursorWidth = OldCursorWidth = New;
  359.                     break;
  360.     }
  361. }
  362.  
  363.     /* ConCharInsert(const UBYTE Char):
  364.      *
  365.      *    Insert a character at the current cursor position.
  366.      */
  367.  
  368. VOID
  369. ConCharInsert(const UBYTE Char)
  370. {
  371.     RedrawInputLine = TRUE;
  372.  
  373.     CursorX += ConCharWidth(Char);
  374. }
  375.  
  376.     /* ConScrollUp():
  377.      *
  378.      *    Scroll the terminal contents one line up.
  379.      */
  380.  
  381. VOID
  382. ConScrollUp()
  383. {
  384.         /* Inside the status line the cursor is always
  385.          * disabled.
  386.          */
  387.  
  388.     if(ConOutputWindow)
  389.         ScrollRaster(RPort,0,TextFontHeight,Window -> BorderLeft,Window -> BorderTop,Window -> Width - (Window -> BorderRight + 1),ConNumStatusLines * TextFontHeight);
  390.     else
  391.     {
  392.             /* Is the cursor enabled? */
  393.  
  394.         if(CursorEnabled)
  395.         {
  396.                 /* Turn the cursor off. */
  397.  
  398.             ConCursorOff();
  399.  
  400.                 /* Scroll the terminal contents up. */
  401.  
  402.             if(gflags . pr_status || ConNumStatusLines > 1)
  403.                 ScrollRaster(RPort,0,TextFontHeight,Window -> BorderLeft,ConNumStatusLines * TextFontHeight + Window -> BorderTop,Window -> Width - (Window -> BorderRight + 1),Window -> Height - (Window -> BorderBottom + 1));
  404.             else
  405.                 ScrollRaster(RPort,0,TextFontHeight,Window -> BorderLeft,Window -> BorderTop,Window -> Width - (Window -> BorderRight + 1),Window -> Height - (Window -> BorderBottom + 1));
  406.  
  407.                 /* Reposition the cursor. */
  408.  
  409.             CursorX = 0;
  410.             CursorY = TextFontHeight * (ConNumLines - 1);
  411.  
  412.                 /* Turn it on again. */
  413.  
  414.             ConCursorOn(CURSOR_NOCHANGE);
  415.         }
  416.         else
  417.         {
  418.                 /* Scroll the terminal contents up. */
  419.  
  420.             if(gflags . pr_status || ConNumStatusLines > 1)
  421.                 ScrollRaster(RPort,0,TextFontHeight,Window -> BorderLeft,ConNumStatusLines * TextFontHeight + Window -> BorderTop,Window -> Width - (Window -> BorderRight + 1),Window -> Height - (Window -> BorderBottom + 1));
  422.             else
  423.                 ScrollRaster(RPort,0,TextFontHeight,Window -> BorderLeft,Window -> BorderTop,Window -> Width - (Window -> BorderRight + 1),Window -> Height - (Window -> BorderBottom + 1));
  424.  
  425.                 /* Reposition the cursor. */
  426.  
  427.             CursorX = 0;
  428.             CursorY = TextFontHeight * (ConNumLines - 1);
  429.         }
  430.     }
  431. }
  432.  
  433.     /* ConWrite(const char *Line,LONG Len,LONG Indent):
  434.      *
  435.      *    Output a text on the terminal.
  436.      */
  437.  
  438. VOID
  439. ConWrite(const char *Line,LONG Len,LONG Indent)
  440. {
  441.         /* Just like console.device, determine the
  442.          * text length if -1 is passed in as the
  443.          * length.
  444.          */
  445.  
  446.     if(Len == -1)
  447.         Len = strlen(Line);
  448.  
  449.         /* Is there anything to print? */
  450.  
  451.     if(Len)
  452.     {
  453.             /* Is the cursor still enabled? */
  454.  
  455.         if(CursorEnabled)
  456.         {
  457.                 /* Turn off the cursor. */
  458.  
  459.             ConCursorOff();
  460.  
  461.                 /* Print the text. */
  462.  
  463.             Move(RPort,Indent + CursorX + Window -> BorderLeft,CursorY + ThisFont -> tf_Baseline + Window -> BorderTop);
  464.             Text(RPort,(STRPTR)Line,Len);
  465.  
  466.                 /* Move up. */
  467.  
  468.             CursorX += TextLength(RPort,(STRPTR)Line,Len);
  469.  
  470.                 /* Turn the cursor back on. */
  471.  
  472.             ConCursorOn(CURSOR_NOCHANGE);
  473.         }
  474.         else
  475.         {
  476.                 /* Print the text. */
  477.  
  478.             Move(RPort,Indent + CursorX + Window -> BorderLeft,CursorY + ThisFont -> tf_Baseline + Window -> BorderTop);
  479.             Text(RPort,(STRPTR)Line,Len);
  480.  
  481.                 /* Move up. */
  482.  
  483.             CursorX += TextLength(RPort,(STRPTR)Line,Len);
  484.         }
  485.     }
  486. }
  487.  
  488.     /* ConRedraw(const int X,const int Y,const STRPTR String,const int Len):
  489.      *
  490.      *    Redraw the input string.
  491.      */
  492.  
  493. VOID
  494. ConRedraw(const int X,const int Y,const STRPTR String,const int Len)
  495. {
  496.         /* Determine width in pixels. */
  497.  
  498.     int Width = TextLength(RPort,(STRPTR)String,Len);
  499.  
  500.         /* Turn the cursor off. */
  501.  
  502.     ConCursorOff();
  503.  
  504.         /* Redraw the input string. */
  505.  
  506.     Move(RPort,X + Window -> BorderLeft,Y + ThisFont -> tf_Baseline + Window -> BorderTop);
  507.     Text(RPort,(STRPTR)String,Len);
  508.  
  509.         /* Clear to end of line. */
  510.  
  511.     if(Width < WindowWidth)
  512.     {
  513.         SetAPen(RPort,ConBackPen);
  514.         RectFill(RPort,X + Width + Window -> BorderLeft,Y + Window -> BorderTop,Window -> Width - (Window -> BorderRight + 1),Y + Window -> BorderTop + TextFontHeight - 1);
  515.         SetAPen(RPort,ConTextPen);
  516.     }
  517.  
  518.         /* Turn the cursor back on. */
  519.  
  520.     ConCursorOn(CURSOR_NOCHANGE);
  521. }
  522.  
  523.     /* ConSetColour(const int Colour):
  524.      *
  525.      *    Set the text rendering colours. If running on a monochrome
  526.      *    display, the colours will be mapped to text style attributes.
  527.      */
  528.  
  529. VOID
  530. ConSetColour(const int Colour)
  531. {
  532.         /* Are we running on a monochrome display? */
  533.  
  534.     Bool IsMono = (Depth == 1 || !NewOS);
  535.  
  536.         /* The following code decides which text rendering colour
  537.          * to set.
  538.          */
  539.  
  540.     switch(Colour)
  541.     {
  542.             /* Text input colour. */
  543.  
  544.         case COLOUR_INPUT:    if(IsMono)
  545.                     {
  546.                         SetAPen(RPort,ConTextPen = 1);
  547.                         SetBPen(RPort,ConBackPen = 0);
  548.  
  549.                         SetSoftStyle(RPort,FS_NORMAL,AskSoftStyle(RPort));
  550.                     }
  551.                     else
  552.                     {
  553.                         SetAPen(RPort,ConTextPen = 2);
  554.                         SetBPen(RPort,ConBackPen = 0);
  555.                     }
  556.  
  557.                     break;
  558.  
  559.             /* Status line colour. */
  560.  
  561.         case COLOUR_STATUS:    if(IsMono)
  562.                     {
  563.                         SetAPen(RPort,ConTextPen = 0);
  564.                         SetBPen(RPort,ConBackPen = 1);
  565.  
  566.                         SetSoftStyle(RPort,FS_NORMAL,AskSoftStyle(RPort));
  567.                     }
  568.                     else
  569.                     {
  570.                         SetAPen(RPort,ConTextPen = 2);
  571.                         SetBPen(RPort,ConBackPen = 3);
  572.                     }
  573.  
  574.                     break;
  575.  
  576.             /* Error message colour. */
  577.  
  578.         case COLOUR_ERROR:    if(IsMono)
  579.                     {
  580.                         SetAPen(RPort,ConTextPen = 1);
  581.                         SetBPen(RPort,ConBackPen = 0);
  582.  
  583.                         SetSoftStyle(RPort,FSF_UNDERLINED,AskSoftStyle(RPort));
  584.                     }
  585.                     else
  586.                     {
  587.                         SetAPen(RPort,ConTextPen = 3);
  588.                         SetBPen(RPort,ConBackPen = 0);
  589.                     }
  590.  
  591.                     break;
  592.  
  593.             /* Special emphasis colour. */
  594.  
  595.         case COLOUR_SPECIAL:    if(IsMono)
  596.                     {
  597.                         SetAPen(RPort,ConTextPen = 1);
  598.                         SetBPen(RPort,ConBackPen = 0);
  599.  
  600.                         SetSoftStyle(RPort,FSF_BOLD,AskSoftStyle(RPort));
  601.                     }
  602.                     else
  603.                     {
  604.                         SetAPen(RPort,ConTextPen = 2);
  605.                         SetBPen(RPort,ConBackPen = 0);
  606.                     }
  607.  
  608.                     break;
  609.  
  610.             /* Standard text colour. */
  611.  
  612.         default:        SetAPen(RPort,ConTextPen = 1);
  613.                     SetBPen(RPort,ConBackPen = 0);
  614.  
  615.                     if(IsMono)
  616.                         SetSoftStyle(RPort,FS_NORMAL,AskSoftStyle(RPort));
  617.  
  618.                     break;
  619.     }
  620. }
  621.  
  622.     /* ConSetKey(const int Key,const STRPTR String,const int Len):
  623.      *
  624.      *    Set a specific function key.
  625.      */
  626.  
  627. VOID
  628. ConSetKey(const int Key,const STRPTR String,const int Len)
  629. {
  630.         /* Is the new string longer than the old one? */
  631.  
  632.     if(FunctionKeys[Key] . sb_Len < Len)
  633.     {
  634.             /* Free previous key assignment. */
  635.  
  636.         free(FunctionKeys[Key] . sb_Buffer);
  637.  
  638.             /* Create new string buffer. */
  639.  
  640.         if(FunctionKeys[Key] . sb_Buffer = (char *)malloc(Len + 1))
  641.         {
  642.                 /* Copy the key string. */
  643.  
  644.             memcpy(FunctionKeys[Key] . sb_Buffer,String,Len);
  645.  
  646.                 /* Provide null-termination. */
  647.  
  648.             FunctionKeys[Key] . sb_Buffer[Len] = 0;
  649.  
  650.                 /* Set string length. */
  651.  
  652.             FunctionKeys[Key] . sb_Len = Len;
  653.         }
  654.         else
  655.             FunctionKeys[Key] . sb_Len = 0;
  656.     }
  657.     else
  658.     {
  659.             /* Install new string. */
  660.  
  661.         if(Len)
  662.         {
  663.                 /* Copy the key string. */
  664.  
  665.             memcpy(FunctionKeys[Key] . sb_Buffer,String,Len);
  666.  
  667.                 /* Provide null-termination. */
  668.  
  669.             FunctionKeys[Key] . sb_Buffer[Len] = 0;
  670.         }
  671.         else
  672.         {
  673.                 /* Zero length, free previous buffer
  674.                  * assignment.
  675.                  */
  676.  
  677.             if(FunctionKeys[Key] . sb_Buffer)
  678.             {
  679.                     /* Free the buffer. */
  680.  
  681.                 free(FunctionKeys[Key] . sb_Buffer);
  682.  
  683.                     /* Clear address pointer. */
  684.  
  685.                 FunctionKeys[Key] . sb_Buffer = NULL;
  686.             }
  687.         }
  688.  
  689.             /* Install new length. */
  690.  
  691.         FunctionKeys[Key] . sb_Len = Len;
  692.     }
  693. }
  694.  
  695.     /* ConCloseLibs():
  696.      *
  697.      *    Close required system libraries.
  698.      */
  699.  
  700. VOID
  701. ConCloseLibs()
  702. {
  703.     if(IntuitionBase)
  704.     {
  705.         CloseLibrary((struct Library *)IntuitionBase);
  706.  
  707.         IntuitionBase = NULL;
  708.     }
  709.  
  710.     if(GfxBase)
  711.     {
  712.         CloseLibrary((struct Library *)GfxBase);
  713.  
  714.         GfxBase = NULL;
  715.     }
  716.  
  717.     if(DiskfontBase)
  718.     {
  719.         CloseLibrary(DiskfontBase);
  720.  
  721.         DiskfontBase = NULL;
  722.     }
  723.  
  724.     if(AslBase)
  725.     {
  726.         CloseLibrary(AslBase);
  727.  
  728.         AslBase = NULL;
  729.     }
  730.  
  731.     if(IconBase)
  732.     {
  733.         CloseLibrary(IconBase);
  734.  
  735.         IconBase = NULL;
  736.     }
  737.  
  738.     if(IFFParseBase)
  739.     {
  740.         CloseLibrary(IFFParseBase);
  741.  
  742.         IFFParseBase = NULL;
  743.     }
  744.  
  745.     if(GadToolsBase)
  746.     {
  747.         CloseLibrary(GadToolsBase);
  748.  
  749.         GadToolsBase = NULL;
  750.     }
  751.  
  752.     if(UtilityBase)
  753.     {
  754.         CloseLibrary(UtilityBase);
  755.  
  756.         UtilityBase = NULL;
  757.     }
  758.  
  759.     if(WorkbenchBase)
  760.     {
  761.         CloseLibrary(WorkbenchBase);
  762.  
  763.         WorkbenchBase = NULL;
  764.     }
  765. }
  766.  
  767.     /* ConOpenLibs():
  768.      *
  769.      *    Open required system libraries.
  770.      */
  771.  
  772. Bool
  773. ConOpenLibs()
  774. {
  775.     if(!LibsOpened)
  776.     {
  777.             /* Remember default window pointer. */
  778.  
  779.         WindowPtr = ThisProcess -> pr_WindowPtr;
  780.  
  781.             /* Make sure that the cleanup routine gets called on exit. */
  782.  
  783.         if(atexit(ConCloseLibs))
  784.             return(FALSE);
  785.  
  786.             /* Open intuition.library. */
  787.  
  788.         if(!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",LIBRARY_MINIMUM)))
  789.             return(FALSE);
  790.  
  791.             /* Open graphics.library. */
  792.  
  793.         if(!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",LIBRARY_MINIMUM)))
  794.             return(FALSE);
  795.  
  796.         DiskfontBase = OpenLibrary("diskfont.library",LIBRARY_MINIMUM);
  797.  
  798.             /* Which operating system revision is this
  799.              * machine currently running?
  800.              */
  801.  
  802.         if(NewOS = (IntuitionBase -> LibNode . lib_Version >= LIB_VERSION))
  803.         {
  804.                 /* Open asl.library (file requester routines). */
  805.  
  806.             if(!(AslBase = OpenLibrary("asl.library",LIB_VERSION)))
  807.                 return(FALSE);
  808.  
  809.                 /* Open icon.library (icon file routines). */
  810.  
  811.             if(!(IconBase = OpenLibrary("icon.library",LIB_VERSION)))
  812.                 return(FALSE);
  813.  
  814.                 /* Open utility.library (string comparison routines). */
  815.  
  816.             if(!(UtilityBase = OpenLibrary("utility.library",LIB_VERSION)))
  817.                 return(FALSE);
  818.  
  819.                 /* Open gadtools.library (menu and gadget creation routines). */
  820.  
  821.             if(!(GadToolsBase = OpenLibrary("gadtools.library",LIB_VERSION)))
  822.                 return(FALSE);
  823.  
  824.                 /* Open iffparse.library (iff file parsing routines). */
  825.  
  826.             if(!(IFFParseBase = OpenLibrary("iffparse.library",LIB_VERSION)))
  827.                 return(FALSE);
  828.  
  829.                 /* Open workbench.library (appwindow routines). */
  830.  
  831.             WorkbenchBase = OpenLibrary("workbench.library",LIB_VERSION);
  832.         }
  833.         else
  834.             IconBase = OpenLibrary("icon.library",LIBRARY_MINIMUM);
  835.     }
  836.  
  837.     return(LibsOpened = TRUE);
  838. }
  839.  
  840.     /* ConCleanup():
  841.      *
  842.      *    Free all resources.
  843.      */
  844.  
  845. VOID
  846. ConCleanup()
  847. {
  848.         /* Free the sound data. */
  849.  
  850.     SoundExit();
  851.  
  852.         /* Close the clipboard. */
  853.  
  854.     ClipClose();
  855.  
  856.         /* Free the timer request. */
  857.  
  858.     if(TimeRequest)
  859.     {
  860.             /* Did we succeed in opening the device? */
  861.  
  862.         if(TimeRequest -> tr_node . io_Device)
  863.         {
  864.                 /* Is the time request still pending? If so, abort it. */
  865.  
  866.             if(!CheckIO((struct IORequest *)TimeRequest))
  867.                 AbortIO((struct IORequest *)TimeRequest);
  868.  
  869.                 /* Remove the request. */
  870.  
  871.             WaitIO((struct IORequest *)TimeRequest);
  872.  
  873.                 /* Close the device. */
  874.  
  875.             CloseDevice((struct IORequest *)TimeRequest);
  876.         }
  877.  
  878.             /* Free the request. */
  879.  
  880.         DeleteExtIO((struct IORequest *)TimeRequest);
  881.     }
  882.  
  883.         /* Free the timer port. */
  884.  
  885.     if(TimePort)
  886.         DeletePort(TimePort);
  887.  
  888.         /* Free the console request. */
  889.  
  890.     if(ConRequest)
  891.     {
  892.             /* Did we open the device? If so, close it. */
  893.  
  894.         if(ConRequest -> io_Device)
  895.             CloseDevice((struct IORequest *)ConRequest);
  896.  
  897.             /* Free the memory. */
  898.  
  899.         FreeMem(ConRequest,sizeof(struct IOStdReq));
  900.     }
  901.  
  902.         /* Free the input conversion buffer. */
  903.  
  904.     if(InputEventBuffer)
  905.         FreeMem(InputEventBuffer,INPUT_LENGTH);
  906.  
  907.         /* Free the fake inputevent. */
  908.  
  909.     if(InputEvent)
  910.         FreeMem(InputEvent,sizeof(struct InputEvent));
  911.  
  912.         /* Remove appwindow link. */
  913.  
  914.     if(WorkbenchWindow)
  915.         RemoveAppWindow(WorkbenchWindow);
  916.  
  917.         /* Remove appwindow msgport and any pending messages. */
  918.  
  919.     if(WorkbenchPort)
  920.     {
  921.         struct Message *Message;
  922.  
  923.         while(Message = GetMsg(WorkbenchPort))
  924.             ReplyMsg(Message);
  925.  
  926.         DeletePort(WorkbenchPort);
  927.     }
  928.  
  929.         /* Close the window. */
  930.  
  931.     if(Window)
  932.     {
  933.             /* Cosmeticism. */
  934.  
  935.         if(Screen)
  936.             ScreenToBack(Screen);
  937.  
  938.             /* Remove the pull-down menus. */
  939.  
  940.         if(Menu)
  941.             ClearMenuStrip(Window);
  942.  
  943.             /* Really close the window. */
  944.  
  945.         CloseWindow(Window);
  946.     }
  947.  
  948.         /* Free the menu strip. */
  949.  
  950.     if(Menu)
  951.         FreeMenus(Menu);
  952.  
  953.         /* Free the chip memory buffer. */
  954.  
  955.     if(ChipData)
  956.         FreeMem(ChipData,sizeof(UWORD) * (sizeof(StopwatchData) + 2));
  957.  
  958.         /* Free the visual information buffer. */
  959.  
  960.     if(VisualInfo)
  961.         FreeVisualInfo(VisualInfo);
  962.  
  963.         /* Close the custom screen if any. */
  964.  
  965.     if(Screen)
  966.         CloseScreen(Screen);
  967.  
  968.         /* Close the disk fonts if any. */
  969.  
  970.     if(TextFont)
  971.         CloseFont(TextFont);
  972.  
  973.     if(ListFont)
  974.         CloseFont(ListFont);
  975.  
  976.         /* Free the file requester. */
  977.  
  978.     if(GameFileRequest)
  979.         FreeAslRequest(GameFileRequest);
  980.  
  981.         /* If not already done, release the lock on the default
  982.          * public screen.
  983.          */
  984.  
  985.     if(DefaultScreen)
  986.         UnlockPubScreen(NULL,DefaultScreen);
  987.  
  988.         /* Reset the DOS requester location. */
  989.  
  990.     if(ThisProcess)
  991.         ThisProcess -> pr_WindowPtr = WindowPtr;
  992. }
  993.  
  994.     /* ConSetup():
  995.      *
  996.      *    Set up console interface.
  997.      */
  998.  
  999. Bool
  1000. ConSetup()
  1001. {
  1002.     struct IBox    ZoomBox;
  1003.     UWORD        Pen    = (UWORD)~0,
  1004.             Width;
  1005.     WORD        MinHeight,
  1006.             MinWidth;
  1007.     UBYTE        Char;
  1008.     ULONG        Total    = 0,
  1009.             Count    = 0;
  1010.     Bool        UseFont    = FALSE;
  1011.  
  1012.         /* Open system libraries. */
  1013.  
  1014.     if(!ConOpenLibs())
  1015.         return(FALSE);
  1016.  
  1017.         /* Create the console info. */
  1018.  
  1019.     if(!(ConRequest = (struct IOStdReq *)AllocMem(sizeof(struct IOStdReq),MEMF_ANY|MEMF_CLEAR)))
  1020.         return(FALSE);
  1021.  
  1022.         /* Open console.device and extract the device base pointer. */
  1023.  
  1024.     if(OpenDevice("console.device",CONU_LIBRARY,(struct IORequest *)ConRequest,NULL))
  1025.         return(FALSE);
  1026.  
  1027.     ConsoleDevice = ConRequest -> io_Device;
  1028.  
  1029.         /* Create the input event auxilary buffers. */
  1030.  
  1031.     if(!(InputEventBuffer = (STRPTR)AllocMem(INPUT_LENGTH,MEMF_ANY)))
  1032.         return(FALSE);
  1033.  
  1034.     if(!(InputEvent = (struct InputEvent *)AllocMem(sizeof(struct InputEvent),MEMF_ANY|MEMF_CLEAR)))
  1035.         return(FALSE);
  1036.  
  1037.         /* Create timer reply port. */
  1038.  
  1039.     if(!(TimePort = CreatePort(NULL,0)))
  1040.         return(FALSE);
  1041.  
  1042.         /* Create timer request. */
  1043.  
  1044.     if(!(TimeRequest = (struct timerequest *)CreateExtIO(TimePort,sizeof(struct timerequest))))
  1045.         return(FALSE);
  1046.  
  1047.         /* Open timer.device */
  1048.  
  1049.     if(OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *)TimeRequest,0))
  1050.         return(FALSE);
  1051.  
  1052.         /* Allocate and set up chip memory data area. */
  1053.  
  1054.     if(!(ChipData = (UWORD *)AllocMem(sizeof(UWORD) * (sizeof(StopwatchData) + 2),MEMF_CHIP)))
  1055.         return(FALSE);
  1056.  
  1057.         /* Fill in the cross-hatch pattern. */
  1058.  
  1059.     ChipData[CHIPDATA_PATTERN  ] = 0x5555;
  1060.     ChipData[CHIPDATA_PATTERN+1] = 0xAAAA;
  1061.  
  1062.         /* Fill in the mouse pointer data. */
  1063.  
  1064.     CopyMem((BYTE *)StopwatchData,(BYTE *)&ChipData[CHIPDATA_POINTER],sizeof(StopwatchData));
  1065.  
  1066.         /* Are we to use special fonts? */
  1067.  
  1068.     if(ListFontName[0] && TextFontName[0] && FontSize && DiskfontBase)
  1069.     {
  1070.             /* Tack on the ".font" suffix. */
  1071.  
  1072.         strcat(ListFontName,".font");
  1073.         strcat(TextFontName,".font");
  1074.  
  1075.             /* Set up the fixed width (`list') font. */
  1076.  
  1077.         ListFontAttr . ta_Name    = ListFontName;
  1078.         ListFontAttr . ta_YSize    = FontSize;
  1079.         ListFontAttr . ta_Style    = FS_NORMAL;
  1080.         ListFontAttr . ta_Flags    = FPF_DISKFONT | FPF_DESIGNED;
  1081.  
  1082.             /* Set up the proportional-spaced (`text') font. */
  1083.  
  1084.         TextFontAttr . ta_Name    = TextFontName;
  1085.         TextFontAttr . ta_YSize    = FontSize;
  1086.         TextFontAttr . ta_Style    = FS_NORMAL;
  1087.         TextFontAttr . ta_Flags    = FPF_DISKFONT | FPF_DESIGNED | FPF_PROPORTIONAL;
  1088.  
  1089.             /* Try to open the fonts. */
  1090.  
  1091.         if((ListFont = OpenDiskFont(&ListFontAttr)) && (TextFont = OpenDiskFont(&TextFontAttr)))
  1092.             UseFont = TRUE;
  1093.     }
  1094.  
  1095.         /* Are we running under control of Kickstart 2.04 or higher? */
  1096.  
  1097.     if(NewOS)
  1098.     {
  1099.             /* Obtain a lock on the default public screen,
  1100.              * we will try to clone it later.
  1101.              */
  1102.  
  1103.         if(!(DefaultScreen = LockPubScreen(NULL)))
  1104.             return(FALSE);
  1105.  
  1106.             /* Are we to open a custom screen? */
  1107.  
  1108.         if(UseCustomScreen)
  1109.         {
  1110.             ULONG    DefaultMode,
  1111.                 Mode;
  1112.  
  1113.                 /* Obtain the default screen display mode. */
  1114.  
  1115.             DefaultMode = GetVPModeID(&DefaultScreen -> ViewPort);
  1116.  
  1117.                 /* Build new display mode ID by looking
  1118.                  * at the default screen display mode
  1119.                  * properties.
  1120.                  */
  1121.  
  1122.             if((DefaultMode & LACE) || ((DefaultMode & MONITOR_ID_MASK) == A2024_MONITOR_ID))
  1123.                 Mode = HIRESLACE_KEY;
  1124.             else
  1125.                 Mode = HIRES_KEY;
  1126.  
  1127.                 /* Determine new screen depth, don't use more
  1128.                  * bit planes than necessary, though.
  1129.                  */
  1130.  
  1131.             if((Depth = DefaultScreen -> RastPort . BitMap -> Depth) > 2)
  1132.                 Depth = 2;
  1133.  
  1134.                 /* Open the custom screen. */
  1135.  
  1136.             if(!(Screen = OpenScreenTags(NULL,
  1137.                 SA_Depth,                Depth,
  1138.                 SA_DisplayID,                Mode,
  1139.                 SA_Overscan,                OSCAN_TEXT,
  1140.                 SA_Pens,                &Pen,
  1141.                 UseFont ? TAG_IGNORE : SA_SysFont,    1,
  1142.                 UseFont ? SA_Font : TAG_IGNORE,        &TextFontAttr,
  1143.                 SA_Title,                SCREEN_TITLE,
  1144.                 SA_AutoScroll,                TRUE,
  1145.                 SA_Behind,                TRUE,
  1146.             TAG_DONE)))
  1147.                 return(FALSE);
  1148.  
  1149.                 /* Open the window on the custom screen. */
  1150.  
  1151.             if(!(Window = OpenWindowTags(NULL,
  1152.                 WA_Left,        0,
  1153.                 WA_Top,            Screen -> BarHeight + 2,
  1154.                 WA_Width,        Screen -> Width,
  1155.                 WA_Height,        Screen -> Height - (Screen -> BarHeight + 2),
  1156.                 WA_Borderless,        TRUE,
  1157.                 WA_Backdrop,        TRUE,
  1158.                 WA_RMBTrap,        TRUE,
  1159.                 WA_NoCareRefresh,    TRUE,
  1160.                 WA_NewLookMenus,    TRUE,
  1161.                 WA_CustomScreen,    Screen,
  1162.                 WA_IDCMP,        IDCMP_MENUPICK | IDCMP_RAWKEY | IDCMP_MOUSEBUTTONS | IDCMP_ACTIVEWINDOW | IDCMP_INACTIVEWINDOW,
  1163.             TAG_DONE)))
  1164.                 return(FALSE);
  1165.         }
  1166.         else
  1167.         {
  1168.             UWORD Width,Height;
  1169.  
  1170.             if(UseFont)
  1171.             {
  1172.                 Width    = DefaultScreen -> WBorLeft + WINDOW_COLUMNS * ListFont -> tf_XSize + DefaultScreen -> WBorRight;
  1173.                 Height    = DefaultScreen -> WBorTop + DefaultScreen -> Font -> ta_YSize + ListFont -> tf_YSize * WINDOW_LINES + DefaultScreen -> WBorBottom;
  1174.             }
  1175.             else
  1176.             {
  1177.                 Width    = DefaultScreen -> WBorLeft + WINDOW_COLUMNS * DefaultScreen -> RastPort . Font -> tf_XSize + DefaultScreen -> WBorRight;
  1178.                 Height    = DefaultScreen -> WBorTop + DefaultScreen -> Font -> ta_YSize * (WINDOW_LINES + 1) + DefaultScreen -> WBorBottom;
  1179.             }
  1180.  
  1181.                 /* Set up the alternative window coordinates and size. */
  1182.  
  1183.             ZoomBox . Left        = 0;
  1184.             ZoomBox . Top        = DefaultScreen -> WBorTop + DefaultScreen -> Font -> ta_YSize + 1;
  1185.             ZoomBox . Width        = DefaultScreen -> Width;
  1186.             ZoomBox . Height    = DefaultScreen -> Height - ZoomBox . Top;
  1187.  
  1188.                 /* Set up the window title. */
  1189.  
  1190.             strcpy(WindowTitle,FilePart((STRPTR)gflags . filenm));
  1191.  
  1192.                 /* Open the window on the Workbench screen. */
  1193.  
  1194.             if(!(Window = OpenWindowTags(NULL,
  1195.                 WA_Title,        WindowTitle,
  1196.                 WA_Width,        Width,
  1197.                 WA_Height,        Height,
  1198.                 WA_MaxWidth,        Width,
  1199.                 WA_MaxHeight,        Height,
  1200.                 WA_MinWidth,        Width,
  1201.                 WA_MinHeight,        Height,
  1202.                 WA_Zoom,        &ZoomBox,
  1203.                 WA_RMBTrap,        TRUE,
  1204.                 WA_DragBar,        TRUE,
  1205.                 WA_DepthGadget,        TRUE,
  1206.                 WA_CloseGadget,        TRUE,
  1207.                 WA_Activate,        TRUE,
  1208.                 WA_SizeGadget,        TRUE,
  1209.                 WA_SizeBBottom,        TRUE,
  1210.                 WA_NoCareRefresh,    TRUE,
  1211.                 WA_NewLookMenus,    TRUE,
  1212.                 WA_CustomScreen,    DefaultScreen,
  1213.                 WA_IDCMP,        IDCMP_CLOSEWINDOW | IDCMP_NEWSIZE | IDCMP_MENUPICK | IDCMP_RAWKEY | IDCMP_MOUSEBUTTONS | IDCMP_ACTIVEWINDOW | IDCMP_INACTIVEWINDOW,
  1214.             TAG_DONE)))
  1215.                 return(FALSE);
  1216.             else
  1217.             {
  1218.                 struct DrawInfo *DrawInfo;
  1219.  
  1220.                 if(DrawInfo = GetScreenDrawInfo(Window -> WScreen))
  1221.                 {
  1222.                     Depth = DrawInfo -> dri_Depth;
  1223.  
  1224.                     FreeScreenDrawInfo(Window -> WScreen,DrawInfo);
  1225.                 }
  1226.                 else
  1227.                     Depth = 1;
  1228.  
  1229.                 SetWindowTitles(Window,(STRPTR)~0,SCREEN_TITLE);
  1230.             }
  1231.         }
  1232.  
  1233.             /* Release the lock on the default public screen. */
  1234.  
  1235.         UnlockPubScreen(NULL,DefaultScreen);
  1236.  
  1237.             /* Clear the address pointer. */
  1238.  
  1239.         DefaultScreen = NULL;
  1240.  
  1241.             /* Allocate the file requester. */
  1242.  
  1243.         if(!(GameFileRequest = AllocAslRequestTags(ASL_FileRequest,
  1244.             ASL_LeftEdge,    Window -> LeftEdge + Window -> Width / 4,
  1245.             ASL_TopEdge,    Window -> TopEdge + Window -> Height / 4,
  1246.             ASL_Width,    Window -> Width / 2,
  1247.             ASL_Height,    Window -> Height / 2,
  1248.         TAG_DONE)))
  1249.             return(FALSE);
  1250.  
  1251.             /* Obtain visual info on our custom screen. */
  1252.  
  1253.         if(!(VisualInfo = GetVisualInfo(Window -> WScreen,TAG_DONE)))
  1254.             return(FALSE);
  1255.  
  1256.             /* Create the pull-down menus. */
  1257.  
  1258.         if(!(Menu = CreateMenus(ConMenuConfig,TAG_DONE)))
  1259.             return(FALSE);
  1260.  
  1261.             /* Properly layout the menus. */
  1262.  
  1263.         if(!(LayoutMenus(Menu,VisualInfo,
  1264.             GTMN_NewLookMenus,    TRUE,
  1265.             GTMN_TextAttr,        Window -> WScreen -> Font,
  1266.         TAG_DONE)))
  1267.             return(FALSE);
  1268.  
  1269.             /* Attach the menus to the window. */
  1270.  
  1271.         SetMenuStrip(Window,Menu);
  1272.  
  1273.             /* Enable the menus. */
  1274.  
  1275.         Window -> Flags &= ~WFLG_RMBTRAP;
  1276.     }
  1277.     else
  1278.     {
  1279.             /* The buffer to hold information on the Workbench screen. */
  1280.  
  1281.         struct Screen        WorkbenchScreen;
  1282.  
  1283.             /* Screen and window allocation data. */
  1284.  
  1285.         struct NewScreen    NewScreen;
  1286.         struct NewWindow    NewWindow;
  1287.  
  1288.             /* Clear the new screen structure. */
  1289.  
  1290.         memset(&NewScreen,0,sizeof(struct NewScreen));
  1291.  
  1292.             /* Fill in the common data. */
  1293.  
  1294.         NewScreen . Depth        = 1;
  1295.         NewScreen . DetailPen        = 0;
  1296.         NewScreen . BlockPen        = 1;
  1297.         NewScreen . DefaultTitle    = SCREEN_TITLE;
  1298.         NewScreen . Type        = CUSTOMSCREEN | SCREENBEHIND;
  1299.  
  1300.         if(UseFont)
  1301.             NewScreen . Font = &TextFontAttr;
  1302.  
  1303.             /* Get the Workbench screen size and display mode. */
  1304.  
  1305.         if(GetScreenData((BYTE *)&WorkbenchScreen,sizeof(struct Screen),WBENCHSCREEN,NULL))
  1306.         {
  1307.             NewScreen . ViewModes    = WorkbenchScreen . ViewPort . Modes;
  1308.             NewScreen . Height    = WorkbenchScreen . Height;
  1309.             NewScreen . Width    = WorkbenchScreen . Width;
  1310.         }
  1311.         else
  1312.             return(FALSE);
  1313.  
  1314.             /* Clear the new window structure. */
  1315.  
  1316.         memset(&NewWindow,0,sizeof(struct NewWindow));
  1317.  
  1318.             /* Fill in the common data. */
  1319.  
  1320.         NewWindow . LeftEdge    = 0;
  1321.         NewWindow . Width    = NewScreen . Width;
  1322.         NewWindow . DetailPen    = (UBYTE)-1;
  1323.         NewWindow . BlockPen    = (UBYTE)-1;
  1324.         NewWindow . IDCMPFlags    = MOUSEBUTTONS | RAWKEY | ACTIVEWINDOW | INACTIVEWINDOW | NEWSIZE | CLOSEWINDOW;
  1325.         NewWindow . MinWidth    = NewWindow . Width;
  1326.         NewWindow . MinHeight    = NewWindow . Height;
  1327.         NewWindow . MaxWidth    = NewWindow . Width;
  1328.         NewWindow . MaxHeight    = NewWindow . Height;
  1329.  
  1330.             /* Are we to open a custom screen? */
  1331.  
  1332.         if(UseCustomScreen)
  1333.         {
  1334.                 /* Default colour palette. */
  1335.  
  1336.             STATIC UWORD Palette[2] = { 0x000,0xEEE };
  1337.  
  1338.                 /* Open the screen. */
  1339.  
  1340.             if(!(Screen = OpenScreen(&NewScreen)))
  1341.                 return(FALSE);
  1342.  
  1343.                 /* Set the screen colours. */
  1344.  
  1345.             LoadRGB4(&Screen -> ViewPort,Palette,2);
  1346.  
  1347.                 /* Set up the remaining window flags. */
  1348.  
  1349.             NewWindow . TopEdge    = Screen -> BarHeight + 1;
  1350.             NewWindow . Height    = Screen -> Height - NewWindow . TopEdge;
  1351.             NewWindow . Flags    = ACTIVATE | RMBTRAP | SMART_REFRESH | NOCAREREFRESH | BORDERLESS | BACKDROP;
  1352.             NewWindow . Screen    = Screen;
  1353.             NewWindow . Type    = CUSTOMSCREEN;
  1354.         }
  1355.         else
  1356.         {
  1357.                 /* Set up the remaining window flags. */
  1358.  
  1359.             NewWindow . TopEdge    = WorkbenchScreen . BarHeight + 1;
  1360.             NewWindow . Height    = NewScreen . Height - NewWindow . TopEdge;
  1361.             NewWindow . Flags    = ACTIVATE | RMBTRAP | SMART_REFRESH | NOCAREREFRESH | WINDOWSIZING | WINDOWDRAG | WINDOWDEPTH | WINDOWCLOSE;
  1362.             NewWindow . Title    = SCREEN_TITLE;
  1363.             NewWindow . Type    = WBENCHSCREEN;
  1364.         }
  1365.  
  1366.             /* Open the window. */
  1367.  
  1368.         if(!(Window = OpenWindow(&NewWindow)))
  1369.             return(FALSE);
  1370.         else
  1371.             Depth = Window -> RPort -> BitMap -> Depth;
  1372.     }
  1373.  
  1374.         /* Let's assume that our window is active now. */
  1375.  
  1376.     WindowIsActive = TRUE;
  1377.  
  1378.         /* Did we open a custom screen? */
  1379.  
  1380.     if(!Screen && WorkbenchBase)
  1381.     {
  1382.             /* Create Workbench appwindow msgport. */
  1383.  
  1384.         if(!(WorkbenchPort = CreatePort(NULL,0)))
  1385.             return(FALSE);
  1386.  
  1387.             /* Create Workbench appwindow link. */
  1388.  
  1389.         if(!(WorkbenchWindow = AddAppWindow(0,0,Window,WorkbenchPort,NULL)))
  1390.             return(FALSE);
  1391.     }
  1392.  
  1393.         /* Determine inner window width. */
  1394.  
  1395.     WindowWidth = Window -> Width - (Window -> BorderLeft + Window -> BorderRight);
  1396.  
  1397.         /* Obtain rastport pointer. */
  1398.  
  1399.     RPort = Window -> RPort;
  1400.  
  1401.         /* Set text rendering mode. */
  1402.  
  1403.     SetDrMd(RPort,JAM2);
  1404.  
  1405.         /* Set text colour. */
  1406.  
  1407.     ConSetColour(COLOUR_TEXT);
  1408.  
  1409.         /* Get both the screen and system default font. The
  1410.          * screen font can be a proportional-spaced font
  1411.          * while the window rastport font is guaranteed
  1412.          * to be a fixed-width font.
  1413.          */
  1414.  
  1415.     if(UseFont)
  1416.     {
  1417.         PropFont    = TextFont;
  1418.         FixedFont    = ListFont;
  1419.     }
  1420.     else
  1421.     {
  1422.         PropFont    = Window -> WScreen -> RastPort . Font;
  1423.         FixedFont    = Window -> IFont;
  1424.     }
  1425.  
  1426.         /* Obtain the system default font dimensions. */
  1427.  
  1428.     TextFontHeight    = FixedFont -> tf_YSize;
  1429.     TextFontWidth    = 0;
  1430.  
  1431.         /* Both the proportional-spaced and the fixed-width
  1432.          * font have to match in height. If this is not the
  1433.          * case, we will use only the fixed-width font.
  1434.          */
  1435.  
  1436.     if(PropFont -> tf_YSize != FixedFont -> tf_YSize)
  1437.         PropFont = FixedFont;
  1438.  
  1439.         /* Set the fixed-width font. */
  1440.  
  1441.     SetFont(RPort,ThisFont = FixedFont);
  1442.  
  1443.         /* Look for the widest glyph. */
  1444.  
  1445.     for(Char = ' ' ; Char <= '~' ; Char++)
  1446.     {
  1447.         if((Width = ConCharWidth(Char)) > TextFontWidth)
  1448.             TextFontWidth = Width;
  1449.  
  1450.             /* Update width. */
  1451.  
  1452.         Total += Width;
  1453.  
  1454.         Count++;
  1455.     }
  1456.  
  1457.         /* Set the proportional-spaced font. */
  1458.  
  1459.     SetFont(RPort,ThisFont = PropFont);
  1460.  
  1461.         /* Look for the widest glyph. */
  1462.  
  1463.     for(Char = ' ' ; Char <= '~' ; Char++)
  1464.     {
  1465.         if((Width = ConCharWidth(Char)) > TextFontWidth)
  1466.             TextFontWidth = Width;
  1467.  
  1468.             /* Update width. */
  1469.  
  1470.         Total += Width;
  1471.  
  1472.         Count++;
  1473.     }
  1474.  
  1475.         /* Determine the average glyph width. */
  1476.  
  1477.     DefaultCursorWidth = Total / Count;
  1478.  
  1479.         /* Determine space character width. */
  1480.  
  1481.     SpaceWidth = ConCharWidth(' ');
  1482.  
  1483.         /* Determine window minimum dimensions. */
  1484.  
  1485.     MinWidth    = Window -> BorderLeft + MIN_WINDOW_COLUMNS * TextFontWidth + Window -> BorderRight;
  1486.     MinHeight    = Window -> BorderTop + MIN_WINDOW_LINES * TextFontHeight + Window -> BorderBottom;
  1487.  
  1488.         /* Set the minimum dimensions if possible. */
  1489.  
  1490.     if(MinWidth < Window -> Width)
  1491.     {
  1492.         if(MinHeight < Window -> Height)
  1493.             WindowLimits(Window,MinWidth,MinHeight,Window -> WScreen -> Width,Window -> WScreen -> Height);
  1494.         else
  1495.             WindowLimits(Window,MinWidth,0,Window -> WScreen -> Width,Window -> WScreen -> Height);
  1496.     }
  1497.     else
  1498.         WindowLimits(Window,0,0,Window -> WScreen -> Width,Window -> WScreen -> Height);
  1499.  
  1500.         /* Remember initial window width. */
  1501.  
  1502.     OldWindowWidth    = Window -> Width;
  1503.     OldWindowHeight    = Window -> Height;
  1504.  
  1505.         /* Redirect DOS requesters. */
  1506.  
  1507.     ThisProcess -> pr_WindowPtr = (APTR)Window;
  1508.  
  1509.         /* Start the timer. */
  1510.  
  1511.     TimeRequest -> tr_node . io_Command    = TR_ADDREQUEST;
  1512.     TimeRequest -> tr_time . tv_secs    = 0;
  1513.     TimeRequest -> tr_time . tv_micro    = SECOND / 2;
  1514.  
  1515.     SendIO((struct IORequest *)TimeRequest);
  1516.  
  1517.         /* Return success. */
  1518.  
  1519.     return(TRUE);
  1520. }
  1521.  
  1522.     /* ConGetChar(Bool SingleKey):
  1523.      *
  1524.      *    Read a single character from the console.
  1525.      */
  1526.  
  1527. UBYTE
  1528. ConGetChar(const Bool SingleKey)
  1529. {
  1530.     struct IntuiMessage    *IntuiMessage;
  1531.     ULONG             Qualifier,
  1532.                  Class,
  1533.                  Code,
  1534.                  Signals;
  1535.     LONG             Len;
  1536.     Bool             GotName = FALSE;
  1537.  
  1538.         /* Provide `fake' input in case we are
  1539.          * returning the result of a function keypress
  1540.          * or a menu event.
  1541.          */
  1542.  
  1543.     if(InputIndex)
  1544.     {
  1545.             /* Did we reach the end of the string?
  1546.              * If so, clear the index pointer and
  1547.              * fall through to the input routine.
  1548.              * If not, return the next character
  1549.              * in the buffer.
  1550.              */
  1551.  
  1552.         if(*InputIndex)
  1553.             return(*InputIndex++);
  1554.         else
  1555.         {
  1556.                 /* Are we to read input from the clipboard? */
  1557.  
  1558.             if(ClipInput)
  1559.             {
  1560.                 LONG Len;
  1561.  
  1562.                     /* Read next data. */
  1563.  
  1564.                 if((Len = ClipRead(InputBuffer,INPUT_LENGTH)) > 0)
  1565.                 {
  1566.                         /* Reset index pointer. */
  1567.  
  1568.                     InputIndex = InputBuffer;
  1569.  
  1570.                         /* Return the next byte. */
  1571.  
  1572.                     return(*InputIndex++);
  1573.                 }
  1574.                 else
  1575.                 {
  1576.                         /* Close the clipboard. */
  1577.  
  1578.                     ClipClose();
  1579.                 }
  1580.             }
  1581.  
  1582.                 /* Clear the buffer pointer. */
  1583.  
  1584.             InputIndex = NULL;
  1585.         }
  1586.     }
  1587.  
  1588.         /* Wait for input... */
  1589.  
  1590.     FOREVER
  1591.     {
  1592.             /* Process all incoming messages. */
  1593.  
  1594.         while(IntuiMessage = (struct IntuiMessage *)GetMsg(Window -> UserPort))
  1595.         {
  1596.                 /* Remember the menu code. */
  1597.  
  1598.             Qualifier    = IntuiMessage -> Qualifier;
  1599.             Class        = IntuiMessage -> Class;
  1600.             Code        = IntuiMessage -> Code;
  1601.  
  1602.                 /* Conver key code to ANSI character or control sequence. */
  1603.  
  1604.             if(Class == IDCMP_RAWKEY)
  1605.             {
  1606.                 InputEvent -> ie_Class            = IECLASS_RAWKEY;
  1607.                 InputEvent -> ie_Code            = Code;
  1608.                 InputEvent -> ie_Qualifier        = Qualifier;
  1609.  
  1610.                     /* Not really an APTR, but let's keep
  1611.                      * it for the sake of compatibility.
  1612.                      */
  1613.  
  1614.                 InputEvent -> ie_position . ie_addr    = *((APTR *)IntuiMessage -> IAddress);
  1615.  
  1616.                     /* Clear the conversion buffer, or the
  1617.                      * conversion result will be appended
  1618.                      * after the current contents.
  1619.                      */
  1620.  
  1621.                 InputEventBuffer[0] = 0;
  1622.  
  1623.                     /* Convert the event. */
  1624.  
  1625.                 Len = RawKeyConvert(InputEvent,InputEventBuffer,INPUT_LENGTH - 1,NULL);
  1626.             }
  1627.             else
  1628.                 Len = 0;
  1629.  
  1630.                 /* Reply the message. */
  1631.  
  1632.             ReplyMsg((struct Message *)IntuiMessage);
  1633.  
  1634.                 /* Did the window size change? */
  1635.  
  1636.             if(Class == IDCMP_NEWSIZE)
  1637.                 return(TERM_RESIZE);
  1638.  
  1639.                 /* Did the window become inactive? */
  1640.  
  1641.             if(Class == IDCMP_INACTIVEWINDOW)
  1642.             {
  1643.                     /* Turn the cursor off. */
  1644.  
  1645.                 ConCursorOff();
  1646.  
  1647.                     /* Remember that the window is
  1648.                      * inactive now.
  1649.                      */
  1650.  
  1651.                 WindowIsActive = FALSE;
  1652.  
  1653.                     /* Turn on the (disabled) cursor. */
  1654.  
  1655.                 ConCursorOn(CURSOR_NOCHANGE);
  1656.             }
  1657.  
  1658.                 /* Did the window become active? */
  1659.  
  1660.             if(Class == IDCMP_ACTIVEWINDOW)
  1661.             {
  1662.                     /* Turn the cursor off. */
  1663.  
  1664.                 ConCursorOff();
  1665.  
  1666.                     /* Remember that the window is
  1667.                      * active now.
  1668.                      */
  1669.  
  1670.                 WindowIsActive = TRUE;
  1671.  
  1672.                     /* Turn on the (enabled) cursor. */
  1673.  
  1674.                 ConCursorOn(CURSOR_NOCHANGE);
  1675.             }
  1676.  
  1677.                 /* Did the user press the close gadget? */
  1678.  
  1679.             if(Class == IDCMP_CLOSEWINDOW && !SingleKey)
  1680.                 return(TERM_CLOSE);
  1681.  
  1682.                 /* Did the user press the select button
  1683.                  * and a single keypress is wanted? If so,
  1684.                  * return a blank space.
  1685.                  */
  1686.  
  1687.             if(Class == IDCMP_MOUSEBUTTONS && SingleKey && Code == SELECTDOWN)
  1688.                 return(' ');
  1689.  
  1690.                 /* Did the user press a key? */
  1691.  
  1692.             if(Class == IDCMP_RAWKEY && Len > 0)
  1693.             {
  1694.                     /* Return a blank space if just a
  1695.                      * keypress is wanted.
  1696.                      */
  1697.  
  1698.                 if(SingleKey)
  1699.                     return(' ');
  1700.                 else
  1701.                 {
  1702.                         /* Provide null-termination. */
  1703.  
  1704.                     InputEventBuffer[Len] = 0;
  1705.  
  1706.                         /* Is this a numeric pad key
  1707.                          * and was no shift key pressed?
  1708.                          */
  1709.  
  1710.                     if((Qualifier & IEQUALIFIER_NUMERICPAD) && !(Qualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT|IEQUALIFIER_CAPSLOCK)))
  1711.                     {
  1712.                             /* Key codes and associated cardinal directions. */
  1713.  
  1714.                         STATIC STRPTR Directions[][2] =
  1715.                         {
  1716.                             "8",    "north\r",
  1717.                             "9",    "ne\r",
  1718.                             "6",    "east\r",
  1719.                             "3",    "se\r",
  1720.                             "2",    "south\r",
  1721.                             "1",    "sw\r",
  1722.                             "4",    "west\r",
  1723.                             "7",    "nw\r",
  1724.  
  1725.                             "[",    "in\r",
  1726.                             "]",    "out\r",
  1727.  
  1728.                             "+",    "up\r",
  1729.                             "-",    "down\r"
  1730.                         };
  1731.  
  1732.                         int i;
  1733.  
  1734.                             /* Run down the list of directions. */
  1735.  
  1736.                         for(i = 0 ; i < sizeof(Directions) / (2 * sizeof(STRPTR)) ; i++)
  1737.                         {
  1738.                                 /* Does it match the input? */
  1739.  
  1740.                             if(!strcmp(Directions[i][0],InputEventBuffer))
  1741.                             {
  1742.                                     /* Use it as fake input. */
  1743.  
  1744.                                 InputIndex = Directions[i][1];
  1745.  
  1746.                                     /* Return ^X. */
  1747.  
  1748.                                 return(TERM_CUT);
  1749.                             }
  1750.                         }
  1751.  
  1752.                             /* Get back to the loop. */
  1753.  
  1754.                         continue;
  1755.                     }
  1756.  
  1757.                         /* Check for special codes, such as
  1758.                          * Shift + Del or Shift + Backspace.
  1759.                          */
  1760.  
  1761.                     if(Qualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
  1762.                     {
  1763.                             /* Delete to end of line? */
  1764.  
  1765.                         if(InputEventBuffer[0] == TERM_DEL)
  1766.                             return(TERM_DELFWD);
  1767.  
  1768.                             /* Delete to start of line? */
  1769.  
  1770.                         if(InputEventBuffer[0] == TERM_BS)
  1771.                             return(TERM_DELBCK);
  1772.                     }
  1773.  
  1774.                         /* Take over the input. */
  1775.  
  1776.                     InputIndex = InputEventBuffer;
  1777.  
  1778.                         /* Return the first character. */
  1779.  
  1780.                     return(*InputIndex++);
  1781.                 }
  1782.             }
  1783.  
  1784.                 /* Process all menu codes, including
  1785.                  * cases of multiple-selection.
  1786.                  */
  1787.  
  1788.             if(Class == IDCMP_MENUPICK)
  1789.             {
  1790.                 struct MenuItem    *Item;
  1791.                 UBYTE         Char = 0;
  1792.  
  1793.                     /* Process all menu selections. */
  1794.  
  1795.                 while(Code != MENUNULL)
  1796.                 {
  1797.                         /* Obtain the address of
  1798.                          * the menu item to belong
  1799.                          * to this menu code.
  1800.                          */
  1801.  
  1802.                     if(Item = ItemAddress(Menu,Code))
  1803.                     {
  1804.                             /* Did we already get
  1805.                              * a suitable menu
  1806.                              * item?
  1807.                              */
  1808.  
  1809.                         if(!Char)
  1810.                         {
  1811.                                 /* Get the new input string. */
  1812.  
  1813.                             if(!(InputIndex = (STRPTR)GTMENUITEM_USERDATA(Item)))
  1814.                             {
  1815.                                     /* Is it the `About...' item? */
  1816.  
  1817.                                 if(Item == ItemAddress(Menu,FULLMENUNUM(MENU_PROJECT,PROJECTMENU_ABOUT,NOSUB)))
  1818.                                 {
  1819.                                         /* Turn the cursor off. */
  1820.  
  1821.                                     ConCursorOff();
  1822.  
  1823.                                         /* Display the information requester. */
  1824.  
  1825.                                     ConAbout();
  1826.  
  1827.                                         /* Turn the cursor back on. */
  1828.  
  1829.                                     ConCursorOn(CURSOR_NOCHANGE);
  1830.                                 }
  1831.  
  1832.                                     /* Is it the `Script...' item? */
  1833.  
  1834.                                 if(Item == ItemAddress(Menu,FULLMENUNUM(MENU_PROJECT,PROJECTMENU_SCRIPT,NOSUB)))
  1835.                                 {
  1836.                                         /* This is probably the scripting command. */
  1837.  
  1838.                                     if(F2_IS_SET(B_SCRIPTING))
  1839.                                         InputIndex = (STRPTR)"Unscript\r";
  1840.                                     else
  1841.                                         InputIndex = (STRPTR)"Script\r";
  1842.  
  1843.                                         /* `Fake' a Ctrl-X
  1844.                                          * to clear the contents
  1845.                                          * of the input line.
  1846.                                          */
  1847.  
  1848.                                     Char = TERM_CUT;
  1849.                                 }
  1850.  
  1851.                                     /* Is it the `Cut' item? */
  1852.  
  1853.                                 if(Item == ItemAddress(Menu,FULLMENUNUM(MENU_EDIT,EDITMENU_CUT,NOSUB)))
  1854.                                     Char = TERM_CUT;
  1855.  
  1856.                                     /* Is it the `Copy' item? */
  1857.  
  1858.                                 if(Item == ItemAddress(Menu,FULLMENUNUM(MENU_EDIT,EDITMENU_COPY,NOSUB)))
  1859.                                     Char = TERM_COPY;
  1860.  
  1861.                                     /* Is it the `Paste' item? */
  1862.  
  1863.                                 if(Item == ItemAddress(Menu,FULLMENUNUM(MENU_EDIT,EDITMENU_PASTE,NOSUB)))
  1864.                                 {
  1865.                                         /* Open the clipboard for reading. */
  1866.  
  1867.                                     if(ClipOpen())
  1868.                                     {
  1869.                                         LONG Len;
  1870.  
  1871.                                             /* Read next data. */
  1872.  
  1873.                                         if((Len = ClipRead(InputBuffer,INPUT_LENGTH)) > 0)
  1874.                                         {
  1875.                                                 /* Reset index pointer. */
  1876.  
  1877.                                             InputIndex = InputBuffer;
  1878.  
  1879.                                                 /* Return the next byte. */
  1880.  
  1881.                                             return(*InputIndex++);
  1882.                                         }
  1883.  
  1884.                                             /* Close the clipboard. */
  1885.  
  1886.                                         ClipClose();
  1887.                                     }
  1888.                                 }
  1889.  
  1890.                                     /* Is it the `Undo' item? */
  1891.  
  1892.                                 if(Item == ItemAddress(Menu,FULLMENUNUM(MENU_EDIT,EDITMENU_UNDO,NOSUB)))
  1893.                                     Char = TERM_UNDO;
  1894.                             }
  1895.                             else
  1896.                             {
  1897.                                     /* `Fake' a Ctrl-X
  1898.                                      * to clear the contents
  1899.                                      * of the input line.
  1900.                                      */
  1901.  
  1902.                                 Char = TERM_CUT;
  1903.                             }
  1904.                         }
  1905.  
  1906.                             /* Proceed to next menu entry. */
  1907.  
  1908.                         Code = Item -> NextSelect;
  1909.                     }
  1910.                 }
  1911.  
  1912.                     /* Did we get anything sensible? If so,
  1913.                      * return immediately.
  1914.                      */
  1915.  
  1916.                 if(Char)
  1917.                     return(Char);
  1918.             }
  1919.         }
  1920.  
  1921.             /* Check the Workbench appwindow. */
  1922.  
  1923.         if(WorkbenchPort)
  1924.         {
  1925.             struct AppMessage *AppMessage;
  1926.  
  1927.             while(AppMessage = (struct AppMessage *)GetMsg(WorkbenchPort))
  1928.             {
  1929.                     /* Do we already have a file name? */
  1930.  
  1931.                 if(!GotName)
  1932.                 {
  1933.                     LONG i;
  1934.  
  1935.                         /* Run down the list of arguments... */
  1936.  
  1937.                     for(i = 0 ; !GotName && i < AppMessage -> am_NumArgs ; i++)
  1938.                     {
  1939.                             /* A correct project icon always has a
  1940.                              * directory lock associated, let's check it.
  1941.                              */
  1942.  
  1943.                         if(AppMessage -> am_ArgList[i] . wa_Lock)
  1944.                         {
  1945.                                 /* Build the project directory name. */
  1946.  
  1947.                             if(NameFromLock(AppMessage -> am_ArgList[i] . wa_Lock,ProjectName,MAX_FILENAME_LENGTH))
  1948.                             {
  1949.                                     /* Add the project name. */
  1950.  
  1951.                                 if(AddPart(ProjectName,AppMessage -> am_ArgList[i] . wa_Name,MAX_FILENAME_LENGTH))
  1952.                                 {
  1953.                                     struct DiskObject *Icon;
  1954.  
  1955.                                         /* Try to read the project icon. */
  1956.  
  1957.                                     if(Icon = GetDiskObject(ProjectName))
  1958.                                     {
  1959.                                             /* Is it really a project icon? */
  1960.  
  1961.                                         if(Icon -> do_Type == WBPROJECT)
  1962.                                         {
  1963.                                             STRPTR Type;
  1964.  
  1965.                                                 /* Find the file type if any. */
  1966.  
  1967.                                             if(Type = FindToolType((STRPTR *)Icon -> do_ToolTypes,"FILETYPE"))
  1968.                                             {
  1969.                                                     /* Is it a bookmark file? */
  1970.  
  1971.                                                 if(MatchToolValue(Type,"BOOKMARK") && MatchToolValue(Type,"ITF"))
  1972.                                                     GotName = TRUE;
  1973.                                             }
  1974.                                         }
  1975.  
  1976.                                             /* Free the icon data. */
  1977.  
  1978.                                         FreeDiskObject(Icon);
  1979.                                     }
  1980.                                 }
  1981.                             }
  1982.                         }
  1983.                     }
  1984.                 }
  1985.  
  1986.                     /* Reply the notification message. */
  1987.  
  1988.                 ReplyMsg((struct Message *)AppMessage);
  1989.             }
  1990.         }
  1991.  
  1992.             /* Did we get a project file name? */
  1993.  
  1994.         if(GotName)
  1995.         {
  1996.                 /* Get the new input string. */
  1997.  
  1998.             InputIndex = (STRPTR)"Restore\r";
  1999.  
  2000.                 /* Return with new input. */
  2001.  
  2002.             return(TERM_CUT);
  2003.         }
  2004.         else
  2005.             ProjectName[0] = 0;
  2006.  
  2007.         do
  2008.         {
  2009.                 /* Wait for input... */
  2010.  
  2011.             Signals = Wait(SIG_WINDOW | SIG_WORKBENCH | SIG_TIME);
  2012.  
  2013.                 /* Did we get a timeout? */
  2014.  
  2015.             if(Signals & SIG_TIME)
  2016.             {
  2017.                     /* Toggle the cursor state
  2018.                      * only if the window is
  2019.                      * really active.
  2020.                      */
  2021.  
  2022.                 if(WindowIsActive)
  2023.                 {
  2024.                         /* Which state is the cursor currently in?
  2025.                          * If it's enabled, turn it off, else
  2026.                          * turn it on.
  2027.                          */
  2028.  
  2029.                     if(CursorEnabled)
  2030.                         ConCursorOff();
  2031.                     else
  2032.                         ConCursorOn(CURSOR_NOCHANGE);
  2033.                 }
  2034.  
  2035.                     /* Wait for timer request to return. */
  2036.  
  2037.                 WaitIO((struct IORequest *)TimeRequest);
  2038.  
  2039.                     /* Restart timer. */
  2040.  
  2041.                 TimeRequest -> tr_node . io_Command    = TR_ADDREQUEST;
  2042.                 TimeRequest -> tr_time . tv_secs    = 0;
  2043.                 TimeRequest -> tr_time . tv_micro    = SECOND / 2;
  2044.  
  2045.                 SendIO((struct IORequest *)TimeRequest);
  2046.             }
  2047.         }
  2048.         while(!(Signals & (SIG_WINDOW | SIG_WORKBENCH)));
  2049.     }
  2050. }
  2051.  
  2052.     /* ConPrintf(const char *Format,...):
  2053.      *
  2054.      *    Print a string on the console, including formatting.
  2055.      */
  2056.  
  2057. VOID
  2058. ConPrintf(const char *Format,...)
  2059. {
  2060.     va_list VarArgs;
  2061.  
  2062.         /* Build the string. */
  2063.  
  2064.     va_start(VarArgs,Format);
  2065.  
  2066.     vsprintf(TempBuffer,Format,VarArgs);
  2067.  
  2068.     va_end(VarArgs);
  2069.  
  2070.         /* Print it. */
  2071.  
  2072.     ConWrite(TempBuffer,-1,0);
  2073. }
  2074.  
  2075.     /* ConSwap(STRPTR a,STRPTR b,int Len):
  2076.      *
  2077.      *    Swap the contents of two string buffers.
  2078.      */
  2079.  
  2080. VOID
  2081. ConSwap(STRPTR a,STRPTR b,int Len)
  2082. {
  2083.     register UBYTE Temp;
  2084.  
  2085.     while(Len--)
  2086.     {
  2087.         Temp    = *a;
  2088.         *a++    = *b;
  2089.         *b++    = Temp;
  2090.     }
  2091. }
  2092.  
  2093.     /* ConInput(char *Prompt,char *Input,const int MaxLen,const Bool DoHistory):
  2094.      *
  2095.      *    Read a line of characters.
  2096.      */
  2097.  
  2098. int
  2099. ConInput(char *Prompt,char *Input,const int MaxLen,const Bool DoHistory)
  2100. {
  2101.         /* Control sequence buffer and length of control sequence. */
  2102.  
  2103.     TEXT         SequenceBuffer[81];
  2104.     int         SequenceLen;
  2105.  
  2106.         /* Input length, current cursor position index, last history buffer. */
  2107.  
  2108.     int         Len        = 0,
  2109.              Index        = 0,
  2110.              HistoryIndex    = LastHistory + 1,
  2111.              i;
  2112.  
  2113.         /* Undo buffer area. */
  2114.  
  2115.     char        *UndoBuffer;
  2116.     int         UndoLen,
  2117.              UndoIndex;
  2118.  
  2119.         /* The character to read. */
  2120.  
  2121.     UBYTE         Char;
  2122.  
  2123.         /* Initial cursor X position. */
  2124.  
  2125.     UWORD         InitialCursorX    = CursorX;
  2126.  
  2127.         /* Loop flag. */
  2128.  
  2129.     Bool         Done        = FALSE;
  2130.  
  2131.         /* Prepare the undo buffer. */
  2132.  
  2133.     UndoBuffer = malloc(MaxLen);
  2134.  
  2135.     UndoLen = UndoIndex = 0;
  2136.  
  2137.         /* Change the font if necessary. */
  2138.  
  2139.     if(ThisFont != PropFont)
  2140.         SetFont(RPort,ThisFont = PropFont);
  2141.  
  2142.         /* Read until done. */
  2143.  
  2144.     do
  2145.     {
  2146.             /* Get a character. */
  2147.  
  2148.         switch(Char = ConGetChar(FALSE))
  2149.         {
  2150.                 /* A function key, a cursor key or the help key. */
  2151.  
  2152.             case TERM_CSI:    SequenceLen = 0;
  2153.  
  2154.                         /* Read the whole sequence if possible,
  2155.                          * up to 80 characters will be accepted.
  2156.                          */
  2157.  
  2158.                     do
  2159.                         SequenceBuffer[SequenceLen++] = Char = ConGetChar(FALSE);
  2160.                     while(SequenceLen < 80 && (Char == ' ' || Char == ';' || Char == '?' || (Char >= '0' && Char <= '9')));
  2161.  
  2162.                         /* Provide null-termination. */
  2163.  
  2164.                     SequenceBuffer[SequenceLen] = 0;
  2165.  
  2166.                         /* Function key. */
  2167.  
  2168.                     if(SequenceBuffer[0] != '?' && SequenceBuffer[SequenceLen - 1] == '~')
  2169.                     {
  2170.                         int Key;
  2171.  
  2172.                             /* Remove the terminating tilde. */
  2173.  
  2174.                         SequenceBuffer[SequenceLen - 1] = 0;
  2175.  
  2176.                             /* Make sure that the function
  2177.                              * key code is in reasonable
  2178.                              * dimensions, some custom
  2179.                              * keyboards have more than
  2180.                              * 20 function keys.
  2181.                              */
  2182.  
  2183.                         if((Key = atoi(SequenceBuffer)) < NUM_FKEYS)
  2184.                         {
  2185.                                 /* Is a string assigned to
  2186.                                  * this function key?
  2187.                                  */
  2188.  
  2189.                             if(FunctionKeys[Key] . sb_Len)
  2190.                             {
  2191.                                 Bool    GotIt = FALSE;
  2192.                                 int    i;
  2193.  
  2194.                                     /* Examine the string and look
  2195.                                      * for a bar or exclamation mark
  2196.                                      * which will terminate the
  2197.                                      * string and produce a carriage-
  2198.                                      * return.
  2199.                                      */
  2200.  
  2201.                                 for(i = 0 ; i < FunctionKeys[Key] . sb_Len ; i++)
  2202.                                 {
  2203.                                         /* Is this the character we are looking for? */
  2204.  
  2205.                                     if(FunctionKeys[Key] . sb_Buffer[i] == '|' || FunctionKeys[Key] . sb_Buffer[i] == '!')
  2206.                                     {
  2207.                                             /* Save the previous input buffer contents. */
  2208.  
  2209.                                         if(Len && UndoBuffer)
  2210.                                             memcpy(UndoBuffer,Input,Len);
  2211.  
  2212.                                         UndoLen        = Len;
  2213.                                         UndoIndex    = Index;
  2214.  
  2215.                                             /* Copy the string. */
  2216.  
  2217.                                         memcpy(InputBuffer,FunctionKeys[Key] . sb_Buffer,i);
  2218.  
  2219.                                             /* Add the carriage-return. */
  2220.  
  2221.                                         InputBuffer[i++] = '\r';
  2222.                                         InputBuffer[i]   = 0;
  2223.  
  2224.                                             /* Stop the search and
  2225.                                              * remember that we got
  2226.                                              * a fitting string.
  2227.                                              */
  2228.  
  2229.                                         GotIt = TRUE;
  2230.  
  2231.                                         break;
  2232.                                     }
  2233.                                 }
  2234.  
  2235.                                     /* Provide new input. */
  2236.  
  2237.                                 if(GotIt)
  2238.                                     InputIndex = InputBuffer;
  2239.                                 else
  2240.                                     InputIndex = FunctionKeys[Key] . sb_Buffer;
  2241.                             }
  2242.                             else
  2243.                                 DisplayBeep(Window -> WScreen);
  2244.                         }
  2245.  
  2246.                         break;
  2247.                     }
  2248.  
  2249.                         /* Help key. */
  2250.  
  2251.                     if(DoHistory && !strcmp(SequenceBuffer,"?~"))
  2252.                     {
  2253.                             /* Which function key is pressed? */
  2254.  
  2255.                         int WhichKey = -1;
  2256.  
  2257.                             /* Do not produce any `fake' input. */
  2258.  
  2259.                         InputIndex = NULL;
  2260.  
  2261.                             /* Reset the text colour. */
  2262.  
  2263.                         ConSetColour(COLOUR_TEXT);
  2264.  
  2265.                         ConCursorOff();
  2266.  
  2267.                             /* Clear the input line. */
  2268.  
  2269.                         ConSet(0,TextFontHeight * (ConNumLines - 1),-1);
  2270.  
  2271.                             /* Ask for the function key to
  2272.                              * assign a string to.
  2273.                              */
  2274.  
  2275.                         ConPrintf("Function key to define: ");
  2276.                         ConClearEOL();
  2277.  
  2278.                         ConCursorOn(CURSOR_NOCHANGE);
  2279.  
  2280.                             /* Is the first character we get
  2281.                              * a control-sequence introducer?
  2282.                              */
  2283.  
  2284.                         if(ConGetChar(FALSE) == TERM_CSI)
  2285.                         {
  2286.                             SequenceLen = 0;
  2287.  
  2288.                                 /* Read the whole sequence if possible,
  2289.                                  * up to 80 characters will be accepted.
  2290.                                  */
  2291.  
  2292.                             do
  2293.                                 SequenceBuffer[SequenceLen++] = Char = ConGetChar(FALSE);
  2294.                             while(SequenceLen < 80 && (Char == ' ' || Char == ';' || Char == '?' || (Char >= '0' && Char <= '9')));
  2295.  
  2296.                                 /* Provide null-termination. */
  2297.  
  2298.                             SequenceBuffer[SequenceLen] = 0;
  2299.  
  2300.                                 /* Did we get a function key code? */
  2301.  
  2302.                             if(SequenceBuffer[0] != '?' && SequenceBuffer[SequenceLen - 1] == '~')
  2303.                             {
  2304.                                     /* The function key we got. */
  2305.  
  2306.                                 int Key;
  2307.  
  2308.                                     /* Remove the terminating tilde. */
  2309.  
  2310.                                 SequenceBuffer[SequenceLen - 1] = 0;
  2311.  
  2312.                                     /* Get the number of the key. */
  2313.  
  2314.                                 if((Key = atoi(SequenceBuffer)) < NUM_FKEYS)
  2315.                                     WhichKey = Key;
  2316.                             }
  2317.                         }
  2318.  
  2319.                         ConCursorOff();
  2320.  
  2321.                             /* Return to input colour. */
  2322.  
  2323.                         ConSetColour(COLOUR_INPUT);
  2324.  
  2325.                             /* Did we get any key? */
  2326.  
  2327.                         if(WhichKey == -1)
  2328.                             ConPrintf("None.");
  2329.                         else
  2330.                         {
  2331.                             int Len;
  2332.  
  2333.                                 /* Print the key name. */
  2334.  
  2335.                             ConPrintf("%sF%d",(WhichKey > 9) ? "Shift " : "",(WhichKey % 10) + 1);
  2336.  
  2337.                                 /* Provide new line. */
  2338.  
  2339.                             ConScrollUp();
  2340.  
  2341.                                 /* Set text colour. */
  2342.  
  2343.                             ConSetColour(COLOUR_TEXT);
  2344.  
  2345.                                 /* Show new prompt. */
  2346.  
  2347.                             ConPrintf("Key text >");
  2348.  
  2349.                             ConCursorOn(CURSOR_NOCHANGE);
  2350.  
  2351.                                 /* Return to input colour. */
  2352.  
  2353.                             ConSetColour(COLOUR_INPUT);
  2354.  
  2355.                             InputIndex = NULL;
  2356.  
  2357.                                 /* Read key assignment. */
  2358.  
  2359.                             Len = ConInput("",InputBuffer,0,FALSE);
  2360.  
  2361.                                 /* Set new key string. */
  2362.  
  2363.                             ConSetKey(WhichKey,InputBuffer,Len);
  2364.  
  2365.                             ConCursorOff();
  2366.                         }
  2367.  
  2368.                             /* Provide new line. */
  2369.  
  2370.                         ConScrollUp();
  2371.  
  2372.                             /* Set text colour. */
  2373.  
  2374.                         ConSetColour(COLOUR_TEXT);
  2375.  
  2376.                             /* Print the prompt string. */
  2377.  
  2378.                         ConPrintf(Prompt);
  2379.  
  2380.                             /* Set input colour. */
  2381.  
  2382.                         ConSetColour(COLOUR_INPUT);
  2383.  
  2384.                             /* Write the entire input line. */
  2385.  
  2386.                         ConWrite(Input,Len,0);
  2387.  
  2388.                             /* Make sure that the
  2389.                              * cursor is placed at
  2390.                              * the end of the input
  2391.                              * line.
  2392.                              */
  2393.  
  2394.                         Index = Len;
  2395.  
  2396.                         InputIndex = NULL;
  2397.  
  2398.                         ConCursorOn(CURSOR_AVERAGE);
  2399.  
  2400.                         break;
  2401.                     }
  2402.  
  2403.                         /* Cursor up: recall previous line in history buffer. */
  2404.  
  2405.                     if(!strcmp(SequenceBuffer,"A"))
  2406.                     {
  2407.                             /* Are any history lines available? */
  2408.  
  2409.                         if(LastHistory != -1)
  2410.                         {
  2411.                             ConCursorOff();
  2412.  
  2413.                                 /* Move cursor back
  2414.                                  * to beginning of
  2415.                                  * line.
  2416.                                  */
  2417.  
  2418.                             if(Index)
  2419.                                 ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),-1);
  2420.  
  2421.                                 /* Clear line. */
  2422.  
  2423.                             ConClearEOL();
  2424.  
  2425.                                 /* Go to previous history line. */
  2426.  
  2427.                             if(HistoryIndex)
  2428.                                 HistoryIndex--;
  2429.  
  2430.                                 /* Save the previous input buffer contents. */
  2431.  
  2432.                             if(Len && UndoBuffer)
  2433.                                 memcpy(UndoBuffer,Input,Len);
  2434.  
  2435.                             UndoLen        = Len;
  2436.                             UndoIndex    = Index;
  2437.  
  2438.                                 /* Determine history line length. */
  2439.  
  2440.                             if(MaxLen)
  2441.                                 Index = Len = MIN(MaxLen,HistoryBuffer[HistoryIndex] . sb_Len);
  2442.                             else
  2443.                                 Index = Len = HistoryBuffer[HistoryIndex] . sb_Len;
  2444.  
  2445.                                 /* Copy the history line over. */
  2446.  
  2447.                             memcpy(Input,HistoryBuffer[HistoryIndex] . sb_Buffer,Len);
  2448.  
  2449.                                 /* Write the line. */
  2450.  
  2451.                             ConWrite(Input,Len,0);
  2452.  
  2453.                             ConCursorOn(CURSOR_NOCHANGE);
  2454.                         }
  2455.  
  2456.                         break;
  2457.                     }
  2458.  
  2459.                         /* Cursor down: recall next line in history buffer. */
  2460.  
  2461.                     if(!strcmp(SequenceBuffer,"B"))
  2462.                     {
  2463.                             /* Are any history lines available? */
  2464.  
  2465.                         if(LastHistory != -1)
  2466.                         {
  2467.                             ConCursorOff();
  2468.  
  2469.                                 /* Are we at the end
  2470.                                  * of the list?
  2471.                                  */
  2472.  
  2473.                             if(HistoryIndex < LastHistory)
  2474.                             {
  2475.                                     /* Move cursor back
  2476.                                      * to beginning of
  2477.                                      * line.
  2478.                                      */
  2479.  
  2480.                                 if(Index)
  2481.                                     ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),-1);
  2482.  
  2483.                                     /* Clear line. */
  2484.  
  2485.                                 ConClearEOL();
  2486.  
  2487.                                     /* Get next history line. */
  2488.  
  2489.                                 HistoryIndex++;
  2490.  
  2491.                                     /* Save the previous input buffer contents. */
  2492.  
  2493.                                 if(Len && UndoBuffer)
  2494.                                     memcpy(UndoBuffer,Input,Len);
  2495.  
  2496.                                 UndoLen        = Len;
  2497.                                 UndoIndex    = Index;
  2498.  
  2499.                                     /* Determine history line length. */
  2500.  
  2501.                                 if(MaxLen)
  2502.                                     Index = Len = MIN(MaxLen,HistoryBuffer[HistoryIndex] . sb_Len);
  2503.                                 else
  2504.                                     Index = Len = HistoryBuffer[HistoryIndex] . sb_Len;
  2505.  
  2506.                                     /* Copy the history line over. */
  2507.  
  2508.                                 memcpy(Input,HistoryBuffer[HistoryIndex] . sb_Buffer,Len);
  2509.  
  2510.                                     /* Write the line. */
  2511.  
  2512.                                 ConWrite(Input,Len,0);
  2513.                             }
  2514.                             else
  2515.                             {
  2516.                                     /* Move cursor back
  2517.                                      * to beginning of
  2518.                                      * line.
  2519.                                      */
  2520.  
  2521.                                 if(Index)
  2522.                                     ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),-1);
  2523.  
  2524.                                     /* Clear line. */
  2525.  
  2526.                                 ConClearEOL();
  2527.  
  2528.                                     /* Save the previous input buffer contents. */
  2529.  
  2530.                                 if(Len && UndoBuffer)
  2531.                                     memcpy(UndoBuffer,Input,Len);
  2532.  
  2533.                                 UndoLen        = Len;
  2534.                                 UndoIndex    = Index;
  2535.  
  2536.                                     /* Nothing in the line buffer right now. */
  2537.  
  2538.                                 Index = Len = 0;
  2539.  
  2540.                                     /* Make sure that `cursor up'
  2541.                                      * will recall the last history
  2542.                                      * line.
  2543.                                      */
  2544.  
  2545.                                 HistoryIndex = LastHistory + 1;
  2546.                             }
  2547.  
  2548.                             ConCursorOn(CURSOR_NOCHANGE);
  2549.                         }
  2550.  
  2551.                         break;
  2552.                     }
  2553.  
  2554.                         /* Shift + cursor up: recall first history line in buffer. */
  2555.  
  2556.                     if(!strcmp(SequenceBuffer,"T"))
  2557.                     {
  2558.                             /* Are any history lines available? */
  2559.  
  2560.                         if(LastHistory != -1)
  2561.                         {
  2562.                             ConCursorOff();
  2563.  
  2564.                                 /* Move cursor back
  2565.                                  * to beginning of
  2566.                                  * line.
  2567.                                  */
  2568.  
  2569.                             if(Index)
  2570.                                 ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),-1);
  2571.  
  2572.                                 /* Clear line. */
  2573.  
  2574.                             ConClearEOL();
  2575.  
  2576.                                 /* Use the first history line. */
  2577.  
  2578.                             HistoryIndex = 0;
  2579.  
  2580.                                 /* Save the previous input buffer contents. */
  2581.  
  2582.                             if(Len && UndoBuffer)
  2583.                                 memcpy(UndoBuffer,Input,Len);
  2584.  
  2585.                             UndoLen        = Len;
  2586.                             UndoIndex    = Index;
  2587.  
  2588.                                 /* Determine history line length. */
  2589.  
  2590.                             if(MaxLen)
  2591.                                 Index = Len = MIN(MaxLen,HistoryBuffer[HistoryIndex] . sb_Len);
  2592.                             else
  2593.                                 Index = Len = HistoryBuffer[HistoryIndex] . sb_Len;
  2594.  
  2595.                                 /* Copy the history line over. */
  2596.  
  2597.                             memcpy(Input,HistoryBuffer[HistoryIndex] . sb_Buffer,Len);
  2598.  
  2599.                                 /* Write the line. */
  2600.  
  2601.                             ConWrite(Input,Len,0);
  2602.  
  2603.                             ConCursorOn(CURSOR_NOCHANGE);
  2604.                         }
  2605.  
  2606.                         break;
  2607.                     }
  2608.  
  2609.                         /* Shift + cursor down: recall last history line. */
  2610.  
  2611.                     if(!strcmp(SequenceBuffer,"S"))
  2612.                     {
  2613.                             /* Are any history lines available? */
  2614.  
  2615.                         if(LastHistory != -1)
  2616.                         {
  2617.                             ConCursorOff();
  2618.  
  2619.                                 /* Move cursor back
  2620.                                  * to beginning of
  2621.                                  * line.
  2622.                                  */
  2623.  
  2624.                             if(Index)
  2625.                                 ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),-1);
  2626.  
  2627.                                 /* Clear line. */
  2628.  
  2629.                             ConClearEOL();
  2630.  
  2631.                                 /* Go to last line in history buffer. */
  2632.  
  2633.                             HistoryIndex = LastHistory;
  2634.  
  2635.                                 /* Save the previous input buffer contents. */
  2636.  
  2637.                             if(Len && UndoBuffer)
  2638.                                 memcpy(UndoBuffer,Input,Len);
  2639.  
  2640.                             UndoLen        = Len;
  2641.                             UndoIndex    = Index;
  2642.  
  2643.                                 /* Determine history line length. */
  2644.  
  2645.                             if(MaxLen)
  2646.                                 Index = Len = MIN(MaxLen,HistoryBuffer[HistoryIndex] . sb_Len);
  2647.                             else
  2648.                                 Index = Len = HistoryBuffer[HistoryIndex] . sb_Len;
  2649.  
  2650.                                 /* Copy the history line over. */
  2651.  
  2652.                             memcpy(Input,HistoryBuffer[HistoryIndex] . sb_Buffer,Len);
  2653.  
  2654.                                 /* Write the line. */
  2655.  
  2656.                             ConWrite(Input,Len,0);
  2657.  
  2658.                             ConCursorOn(CURSOR_NOCHANGE);
  2659.                         }
  2660.  
  2661.                         break;
  2662.                     }
  2663.  
  2664.                         /* Cursor right: move cursor to the right. */
  2665.  
  2666.                     if(!strcmp(SequenceBuffer,"C"))
  2667.                     {
  2668.                             /* Are we at the end of the line? */
  2669.  
  2670.                         if(Index < Len)
  2671.                         {
  2672.                             if(Index == Len - 1)
  2673.                                 ConMove(ConCharWidth(Input[Index]),-1);
  2674.                             else
  2675.                                 ConMove(ConCharWidth(Input[Index]),ConCharWidth(Input[Index + 1]));
  2676.  
  2677.                             Index++;
  2678.                         }
  2679.  
  2680.                         break;
  2681.                     }
  2682.  
  2683.                         /* Cursor left: move cursor to the left. */
  2684.  
  2685.                     if(!strcmp(SequenceBuffer,"D"))
  2686.                     {
  2687.                             /* Are we at the beginning of the line? */
  2688.  
  2689.                         if(Index > 0)
  2690.                         {
  2691.                                 /* Update internal cursor position. */
  2692.  
  2693.                             Index--;
  2694.  
  2695.                                 /* Move cursor to the left. */
  2696.  
  2697.                             ConMove(-ConCharWidth(Input[Index]),ConCharWidth(Input[Index]));
  2698.                         }
  2699.  
  2700.                         break;
  2701.                     }
  2702.  
  2703.                         /* Shift + cursor right: move cursor to end of line. */
  2704.  
  2705.                     if(!strcmp(SequenceBuffer," @"))
  2706.                     {
  2707.                             /* Are we at the end of the line? */
  2708.  
  2709.                         if(Index < Len)
  2710.                         {
  2711.                                 /* Move cursor to end of line. */
  2712.  
  2713.                             ConMove(TextLength(RPort,&Input[Index],Len - Index),-1);
  2714.  
  2715.                                 /* Update internal cursor position. */
  2716.  
  2717.                             Index = Len;
  2718.                         }
  2719.  
  2720.                         break;
  2721.                     }
  2722.  
  2723.                         /* Shift + cursor left: move cursor to beginning of line. */
  2724.  
  2725.                     if(!strcmp(SequenceBuffer," A"))
  2726.                     {
  2727.                             /* Are we at the beginning of the line? */
  2728.  
  2729.                         if(Index > 0)
  2730.                         {
  2731.                                 /* Move cursor to beginning of line. */
  2732.  
  2733.                             if(Len)
  2734.                                 ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),ConCharWidth(Input[0]));
  2735.                             else
  2736.                                 ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),-1);
  2737.  
  2738.                                 /* Update internal cursor position. */
  2739.  
  2740.                             Index = 0;
  2741.                         }
  2742.                     }
  2743.  
  2744.                     break;
  2745.  
  2746.                 /* Control-A: move cursor to beginning of line. */
  2747.  
  2748.             case TERM_BEGIN:
  2749.  
  2750.                     if(Index > 0)
  2751.                     {
  2752.                             /* Move cursor to beginning of line. */
  2753.  
  2754.                         if(Len)
  2755.                             ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),ConCharWidth(Input[0]));
  2756.                         else
  2757.                             ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),-1);
  2758.  
  2759.                             /* Update internal cursor position. */
  2760.  
  2761.                         Index = 0;
  2762.                     }
  2763.  
  2764.                     break;
  2765.  
  2766.                 /* Control-Z: move cursor to end of line. */
  2767.  
  2768.             case TERM_END:    if(Index < Len)
  2769.                     {
  2770.                             /* Move cursor to end of line. */
  2771.  
  2772.                         ConMove(TextLength(RPort,&Input[Index],Len - Index),-1);
  2773.  
  2774.                             /* Update internal cursor position. */
  2775.  
  2776.                         Index = Len;
  2777.                     }
  2778.  
  2779.                     break;
  2780.  
  2781.                 /* Backspace: delete the character to the left
  2782.                  * of the cursor.
  2783.                  */
  2784.  
  2785.             case TERM_BS:    if(Index > 0)
  2786.                     {
  2787.                             /* Save the previous input buffer contents. */
  2788.  
  2789.                         if(Len && UndoBuffer)
  2790.                             memcpy(UndoBuffer,Input,Len);
  2791.  
  2792.                         UndoLen        = Len;
  2793.                         UndoIndex    = Index;
  2794.  
  2795.                             /* Delete the character. */
  2796.  
  2797.                         if(Index == Len)
  2798.                             ConCharBackspace(ConCharWidth(Input[Index - 1]),-1);
  2799.                         else
  2800.                             ConCharBackspace(ConCharWidth(Input[Index - 1]),ConCharWidth(Input[Index]));
  2801.  
  2802.                             /* Move line contents. */
  2803.  
  2804.                         for(i = Index - 1 ; i < Len - 1 ; i++)
  2805.                             Input[i] = Input[i + 1];
  2806.  
  2807.                             /* Update internal cursor position. */
  2808.  
  2809.                         Index--;
  2810.  
  2811.                             /* Update line length. */
  2812.  
  2813.                         Len--;
  2814.                     }
  2815.  
  2816.                     break;
  2817.  
  2818.                 /* Delete: delete the character under the cursor. */
  2819.  
  2820.             case TERM_DEL:    if(Index < Len)
  2821.                     {
  2822.                             /* Save the previous input buffer contents. */
  2823.  
  2824.                         if(Len && UndoBuffer)
  2825.                             memcpy(UndoBuffer,Input,Len);
  2826.  
  2827.                         UndoLen        = Len;
  2828.                         UndoIndex    = Index;
  2829.  
  2830.                             /* Delete the character. */
  2831.  
  2832.                         if(Index == Len - 1)
  2833.                             ConCharDelete(CURSOR_AVERAGE);
  2834.                         else
  2835.                             ConCharDelete(ConCharWidth(Input[Index + 1]));
  2836.  
  2837.                             /* Move line contents. */
  2838.  
  2839.                         for(i = Index ; i < Len - 1 ; i++)
  2840.                             Input[i] = Input[i + 1];
  2841.  
  2842.                             /* Update line length. */
  2843.  
  2844.                         Len--;
  2845.                     }
  2846.  
  2847.                     break;
  2848.  
  2849.                 /* Control-C: copy input line. */
  2850.  
  2851.             case TERM_COPY:    if(UndoBuffer)
  2852.                     {
  2853.                         if(Len && UndoBuffer)
  2854.                             memcpy(UndoBuffer,Input,Len);
  2855.  
  2856.                         UndoLen        = Len;
  2857.                         UndoIndex    = Index;
  2858.                     }
  2859.                     else
  2860.                         DisplayBeep(Window -> WScreen);
  2861.  
  2862.                     if(Len)
  2863.                         ClipSave(Input,Len);
  2864.  
  2865.                     break;
  2866.  
  2867.                 /* Control-Y: undo previous editing action. */
  2868.  
  2869.             case TERM_UNDO:    if(UndoBuffer)
  2870.                     {
  2871.                         int OldLen,OldIndex;
  2872.  
  2873.                         if(Len > 0)
  2874.                         {
  2875.                                 /* Move to beginning of line. */
  2876.     
  2877.                             if(Index)
  2878.                                 ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),-1);
  2879.     
  2880.                                 /* Clear line contents. */
  2881.     
  2882.                             ConClearEOL();
  2883.                         }
  2884.     
  2885.                             /* Set new cursor size. */
  2886.     
  2887.                         ConCursorOff();
  2888.                         ConCursorOn(CURSOR_AVERAGE);
  2889.     
  2890.                             /* Copy the input line. */
  2891.  
  2892.                         ConSwap(Input,UndoBuffer,MaxLen);
  2893.     
  2894.                             /* Restore length and index. */
  2895.     
  2896.                         OldLen        = Len;
  2897.                         OldIndex    = Index;
  2898.  
  2899.                         Len        = UndoLen;
  2900.                         Index        = UndoIndex;
  2901.  
  2902.                         UndoLen        = OldLen;
  2903.                         UndoIndex    = OldIndex;
  2904.     
  2905.                             /* Move the cursor. */
  2906.  
  2907.                         if(Index && Len)
  2908.                         {
  2909.                             if(Index == Len)
  2910.                                 ConSet(InitialCursorX + TextLength(RPort,Input,Index),TextFontHeight * (ConNumLines - 1),CURSOR_AVERAGE);
  2911.                             else
  2912.                             {
  2913.                                 if(Index)
  2914.                                     ConSet(InitialCursorX + TextLength(RPort,Input,Index),TextFontHeight * (ConNumLines - 1),ConCharWidth(Input[Index]));
  2915.                                 else
  2916.                                     ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),ConCharWidth(Input[Index]));
  2917.                             }
  2918.                         }
  2919.  
  2920.                             /* Redraw the input line. */
  2921.     
  2922.                         RedrawInputLine = TRUE;
  2923.                     }
  2924.                     else
  2925.                         DisplayBeep(Window -> WScreen);
  2926.  
  2927.                     break;
  2928.  
  2929.                 /* Control-K: delete everything from the cursor forward
  2930.                  * to the end of the line.
  2931.                  */
  2932.  
  2933.             case TERM_DELFWD:
  2934.  
  2935.                         /* Save the previous input buffer contents. */
  2936.  
  2937.                     if(Len && UndoBuffer)
  2938.                         memcpy(UndoBuffer,Input,Len);
  2939.  
  2940.                     UndoLen        = Len;
  2941.                     UndoIndex    = Index;
  2942.  
  2943.                         /* Cut off the remaining line. */
  2944.  
  2945.                     Len = Index;
  2946.  
  2947.                         /* Set new cursor size. */
  2948.  
  2949.                     ConCursorOff();
  2950.                     ConCursorOn(CURSOR_AVERAGE);
  2951.  
  2952.                         /* Redraw the input line. */
  2953.  
  2954.                     RedrawInputLine = TRUE;
  2955.  
  2956.                     break;
  2957.  
  2958.                 /* Control-U: delete everything from the cursor backward
  2959.                  * to the start of the line.
  2960.                  */
  2961.  
  2962.             case TERM_DELBCK:
  2963.  
  2964.                         /* Save the previous input buffer contents. */
  2965.  
  2966.                     if(Len && UndoBuffer)
  2967.                         memcpy(UndoBuffer,Input,Len);
  2968.  
  2969.                     UndoLen        = Len;
  2970.                     UndoIndex    = Index;
  2971.  
  2972.                         /* Is there anything to clear? */
  2973.  
  2974.                     if(Index > 0 && Len > 0)
  2975.                     {
  2976.                             /* Are we to clear the entire line? */
  2977.  
  2978.                         if(Index == Len)
  2979.                         {
  2980.                                 /* Move to beginning of line. */
  2981.     
  2982.                             ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),-1);
  2983.     
  2984.                                 /* Clear line contents. */
  2985.     
  2986.                             ConClearEOL();
  2987.     
  2988.                                 /* Nothing in the line buffer right now. */
  2989.     
  2990.                             Index = Len = 0;
  2991.                         }
  2992.                         else
  2993.                         {
  2994.                                 /* Move line contents. */
  2995.     
  2996.                             for(i = 0 ; i < Len - Index ; i++)
  2997.                                 Input[i] = Input[Index + i];
  2998.     
  2999.                                 /* Move to beginning of line. */
  3000.     
  3001.                             ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),-1);
  3002.     
  3003.                                 /* Update length and index. */
  3004.  
  3005.                             Len    -= Index;
  3006.                             Index     = 0;
  3007.  
  3008.                                 /* Redraw the input line. */
  3009.  
  3010.                             RedrawInputLine = TRUE;
  3011.                         }
  3012.                     }
  3013.  
  3014.                     break;
  3015.  
  3016.                 /* Control-W: delete the word to the left of the cursor. */
  3017.  
  3018.             case TERM_DELWORD:
  3019.  
  3020.                         /* Anything to delete? */
  3021.  
  3022.                     if(Len > 0 && Index > 0)
  3023.                     {
  3024.                         int Diff,Offset = Index - 1;
  3025.  
  3026.                             /* Save the previous input buffer contents. */
  3027.  
  3028.                         if(Len && UndoBuffer)
  3029.                             memcpy(UndoBuffer,Input,Len);
  3030.  
  3031.                         UndoLen        = Len;
  3032.                         UndoIndex    = Index;
  3033.  
  3034.                             /* Find the start of the previous word. */
  3035.  
  3036.                         for(i = Index - 1 ; i >= 0 ; i--)
  3037.                         {
  3038.                             if(i)
  3039.                             {
  3040.                                 if(Input[i] == ' ')
  3041.                                 {
  3042.                                     Offset = i + 1;
  3043.  
  3044.                                     break;
  3045.                                 }
  3046.                             }
  3047.                             else
  3048.                             {
  3049.                                 Offset = i;
  3050.  
  3051.                                 break;
  3052.                             }
  3053.  
  3054.                         }
  3055.  
  3056.                             /* Too much to move? */
  3057.  
  3058.                         if(!(Diff = Index - Offset))
  3059.                         {
  3060.                             Diff    = 1;
  3061.                             Offset    = Index - 1;
  3062.                         }
  3063.  
  3064.                             /* Move the line over. */
  3065.  
  3066.                         for(i = Offset ; i < Len - Diff ; i++)
  3067.                             Input[i] = Input[i + Diff];
  3068.  
  3069.                         Index    -= Diff;
  3070.                         Len    -= Diff;
  3071.  
  3072.                             /* Move the cursor. */
  3073.  
  3074.                         if(Index)
  3075.                             ConSet(InitialCursorX + TextLength(RPort,Input,Index),TextFontHeight * (ConNumLines - 1),ConCharWidth(Input[Index]));
  3076.                         else
  3077.                             ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),ConCharWidth(Input[Index]));
  3078.  
  3079.                             /* Redraw the input line. */
  3080.  
  3081.                         RedrawInputLine = TRUE;
  3082.                     }
  3083.  
  3084.                     break;
  3085.  
  3086.                 /* Control-\: close the window. */
  3087.  
  3088.             case TERM_CLOSE:
  3089.  
  3090.                     if(Len > 0)
  3091.                     {
  3092.                             /* Move to beginning of line. */
  3093.  
  3094.                         if(Index)
  3095.                             ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),-1);
  3096.  
  3097.                             /* Clear line contents. */
  3098.  
  3099.                         ConClearEOL();
  3100.  
  3101.                             /* Nothing in the line buffer right now. */
  3102.  
  3103.                         Index = Len = 0;
  3104.                     }
  3105.  
  3106.                         /* Drop clipboard processing. */
  3107.  
  3108.                     ClipClose();
  3109.  
  3110.                         /* Provide fake input. */
  3111.  
  3112.                     InputIndex = "Quit\r";
  3113.  
  3114.                     break;
  3115.  
  3116.                 /* Control-X: delete the entire line contents. */
  3117.  
  3118.             case TERM_CUT:    if(Len > 0)
  3119.                     {
  3120.                         ClipSave(Input,Len);
  3121.  
  3122.                             /* Save the previous input buffer contents. */
  3123.  
  3124.                         if(UndoBuffer)
  3125.                             memcpy(UndoBuffer,Input,Len);
  3126.  
  3127.                         UndoLen        = Len;
  3128.                         UndoIndex    = Index;
  3129.  
  3130.                             /* Move to beginning of line. */
  3131.  
  3132.                         if(Index)
  3133.                             ConSet(InitialCursorX,TextFontHeight * (ConNumLines - 1),-1);
  3134.  
  3135.                             /* Clear line contents. */
  3136.  
  3137.                         ConClearEOL();
  3138.  
  3139.                             /* Nothing in the line buffer right now. */
  3140.  
  3141.                         Index = Len = 0;
  3142.                     }
  3143.  
  3144.                     break;
  3145.  
  3146.                 /* Carriage return: terminate input. */
  3147.  
  3148.             case TERM_CR:    Done = TRUE;
  3149.  
  3150.                     break;
  3151.  
  3152.                 /* Form feed: window was resized. */
  3153.  
  3154.             case TERM_RESIZE:
  3155.  
  3156.                     if(Window -> Width != OldWindowWidth || Window -> Height != OldWindowHeight)
  3157.                     {
  3158.                         Bool NewPrompt = FALSE;
  3159.  
  3160.                             /* Has the width changed? */
  3161.  
  3162.                         if(Window -> Width != OldWindowWidth)
  3163.                         {
  3164.                                 /* Determine new window width. */
  3165.  
  3166.                             WindowWidth = Window -> Width - (Window -> BorderLeft + Window -> BorderRight);
  3167.  
  3168.                                 /* If the input line has become
  3169.                                  * too long for the window to
  3170.                                  * hold, trim it.
  3171.                                  */
  3172.  
  3173.                             if(InitialCursorX + TextLength(RPort,Input,Len) + TextFontWidth + ConCharWidth(Char) >= WindowWidth)
  3174.                             {
  3175.                                 while(Len > 0 && InitialCursorX + TextLength(RPort,Input,Len) + TextFontWidth + ConCharWidth(Char) >= WindowWidth)
  3176.                                     Len--;
  3177.  
  3178.                                     /* Turn off the cursor. */
  3179.  
  3180.                                 ConCursorOff();
  3181.  
  3182.                                     /* Is the prompt too long? If so,
  3183.                                      * use a single character.
  3184.                                      */
  3185.  
  3186.                                 if(Len < 0)
  3187.                                 {
  3188.                                     InitialCursorX = ConCharWidth('>');
  3189.  
  3190.                                     Prompt = ">";
  3191.                                 }
  3192.  
  3193.                                     /* Redraw prompt and input string. */
  3194.  
  3195.                                 NewPrompt = TRUE;
  3196.                             }
  3197.  
  3198.                                 /* Remember new window width. */
  3199.  
  3200.                             OldWindowWidth = Window -> Width;
  3201.  
  3202.                                 /* Print the score line. */
  3203.  
  3204.                             scr_putscore();
  3205.                         }
  3206.  
  3207.                             /* Has the height changed? */
  3208.  
  3209.                         if(Window -> Height != OldWindowHeight)
  3210.                         {
  3211.                             WORD Remainder;
  3212.  
  3213.                                 /* Has the window become less high?
  3214.                                  * If so, clear the area below the
  3215.                                  * input line.
  3216.                                  */
  3217.  
  3218.                             if((Remainder = Window -> Height - (Window -> BorderTop + ConNumLines * TextFontHeight + Window -> BorderBottom)) > 0)
  3219.                             {
  3220.                                 SetAPen(RPort,ConBackPen);
  3221.                                 RectFill(RPort,Window -> BorderLeft,Window -> Height - (Window -> BorderBottom + Remainder),Window -> Width - (Window -> BorderRight + 1),Window -> Height - (Window -> BorderBottom + 1));
  3222.                                 SetAPen(RPort,ConTextPen);
  3223.                             }
  3224.  
  3225.                                 /* Turn the cursor off. */
  3226.  
  3227.                             ConCursorOff();
  3228.  
  3229.                                 /* If the window has become higher,
  3230.                                  * erase the previous prompt.
  3231.                                  */
  3232.  
  3233.                             if(Window -> Height > OldWindowHeight)
  3234.                             {
  3235.                                 ConSet(0,TextFontHeight * (ConNumLines - 1),-1);
  3236.  
  3237.                                 ConClearEOL();
  3238.                             }
  3239.  
  3240.                                 /* Determine new number of lines. */
  3241.  
  3242.                             ConNumLines = (Window -> Height - (Window -> BorderTop + Window -> BorderBottom)) / TextFontHeight;
  3243.  
  3244.                                 /* Redraw both prompt and input string. */
  3245.  
  3246.                             NewPrompt = TRUE;
  3247.  
  3248.                                 /* Remember new window height. */
  3249.  
  3250.                             OldWindowHeight = Window -> Height;
  3251.  
  3252.                                 /* Clear the area below the input line. */
  3253.  
  3254.                             if((Remainder = Window -> Height - (Window -> BorderTop + ConNumLines * TextFontHeight + Window -> BorderBottom)) > 0)
  3255.                             {
  3256.                                 SetAPen(RPort,ConBackPen);
  3257.                                 RectFill(RPort,Window -> BorderLeft,Window -> Height - (Window -> BorderBottom + Remainder),Window -> Width - (Window -> BorderRight + 1),Window -> Height - (Window -> BorderBottom + 1));
  3258.                                 SetAPen(RPort,ConTextPen);
  3259.                             }
  3260.                         }
  3261.  
  3262.                             /* Are we to redraw prompt and input string? */
  3263.  
  3264.                         if(NewPrompt)
  3265.                         {
  3266.                                 /* Move to bottom of window. */
  3267.  
  3268.                             ConSet(0,TextFontHeight * (ConNumLines - 1),-1);
  3269.  
  3270.                                 /* Set text colour. */
  3271.  
  3272.                             ConSetColour(COLOUR_TEXT);
  3273.  
  3274.                                 /* Print the prompt string. */
  3275.  
  3276.                             ConPrintf(Prompt);
  3277.  
  3278.                                 /* Set input colour. */
  3279.  
  3280.                             ConSetColour(COLOUR_INPUT);
  3281.  
  3282.                                 /* Write the entire input line. */
  3283.  
  3284.                             ConWrite(Input,Len,0);
  3285.  
  3286.                                 /* Clear the rest of the line. */
  3287.  
  3288.                             ConClearEOL();
  3289.  
  3290.                                 /* Make sure that the
  3291.                                  * cursor is placed at
  3292.                                  * the end of the input
  3293.                                  * line.
  3294.                                  */
  3295.  
  3296.                             Index = Len;
  3297.  
  3298.                             InputIndex = NULL;
  3299.  
  3300.                             ConCursorOn(CURSOR_AVERAGE);
  3301.                         }
  3302.                     }
  3303.  
  3304.                     break;
  3305.  
  3306.                 /* If suitable, store the character entered. */
  3307.  
  3308.             default:    if(Char >= 32 && Char <= 126)
  3309.                     {
  3310.                             /* Is there a length limit? */
  3311.  
  3312.                         if(!MaxLen || Len < MaxLen)
  3313.                         {
  3314.                                 /* If the resulting string will become
  3315.                                  * too long to fit in the window, don't
  3316.                                  * store the new character.
  3317.                                  */
  3318.  
  3319.                             if(InitialCursorX + TextLength(RPort,Input,Len) + TextFontWidth + ConCharWidth(Char) < WindowWidth)
  3320.                             {
  3321.                                     /* Save the previous input buffer contents. */
  3322.  
  3323.                                 if(Len && UndoBuffer)
  3324.                                     memcpy(UndoBuffer,Input,Len);
  3325.  
  3326.                                 UndoLen        = Len;
  3327.                                 UndoIndex    = Index;
  3328.  
  3329.                                     /* Print the character. */
  3330.  
  3331.                                 ConCharInsert(Char);
  3332.  
  3333.                                     /* Move line contents up if
  3334.                                      * necessary.
  3335.                                      */
  3336.  
  3337.                                 if(Index < Len)
  3338.                                 {
  3339.                                     for(i = Len ; i > Index ; i--)
  3340.                                         Input[i] = Input[i - 1];
  3341.                                 }
  3342.  
  3343.                                     /* Store the character. */
  3344.  
  3345.                                 Input[Index++] = Char;
  3346.  
  3347.                                     /* Update line length. */
  3348.  
  3349.                                 Len++;
  3350.                             }
  3351.                         }
  3352.                     }
  3353.  
  3354.                     break;
  3355.         }
  3356.  
  3357.             /* Are we to redraw the input line? */
  3358.  
  3359.         if(RedrawInputLine)
  3360.         {
  3361.             ConRedraw(InitialCursorX,TextFontHeight * (ConNumLines - 1),Input,Len);
  3362.  
  3363.             RedrawInputLine = FALSE;
  3364.         }
  3365.     }
  3366.     while(!Done);
  3367.  
  3368.         /* Did the user enter anything? */
  3369.  
  3370.     if(Len && DoHistory)
  3371.     {
  3372.             /* Move up if space is exhausted. */
  3373.  
  3374.         if(LastHistory == HISTORY_LINES - 1)
  3375.         {
  3376.                 /* Free first line in history buffer. */
  3377.  
  3378.             free(HistoryBuffer[0] . sb_Buffer);
  3379.  
  3380.                 /* Move previous contents up. */
  3381.  
  3382.             for(i = 1 ; i < HISTORY_LINES ; i++)
  3383.                 HistoryBuffer[i - 1] = HistoryBuffer[i];
  3384.         }
  3385.         else
  3386.             LastHistory++;
  3387.  
  3388.             /* Add next history line. */
  3389.  
  3390.         if(HistoryBuffer[LastHistory] . sb_Buffer = (char *)malloc(Len))
  3391.         {
  3392.                 /* Copy the input line. */
  3393.  
  3394.             memcpy(HistoryBuffer[LastHistory] . sb_Buffer,Input,Len);
  3395.  
  3396.                 /* Save the line length. */
  3397.  
  3398.             HistoryBuffer[LastHistory] . sb_Len = Len;
  3399.         }
  3400.         else
  3401.             LastHistory--;
  3402.     }
  3403.  
  3404.         /* Drop the undo buffer. */
  3405.  
  3406.     if(UndoBuffer)
  3407.         free(UndoBuffer);
  3408.  
  3409.         /* Close the clipboard, we don't want multiple
  3410.          * lines to be returned.
  3411.          */
  3412.  
  3413.     ClipClose();
  3414.  
  3415.         /* Return number of characters entered. */
  3416.  
  3417.     return(Len);
  3418. }
  3419.  
  3420.     /* ConPrintStatus(const char *Left,const char *Right):
  3421.      *
  3422.      *    Print the status line.
  3423.      */
  3424.  
  3425. VOID
  3426. ConPrintStatus(const char *Left,const char *Right)
  3427. {
  3428.     int    LeftLen,    RightLen,
  3429.         LeftWidth,    RightWidth,
  3430.  
  3431.         Width;
  3432.  
  3433.         /* Change the font if necessary. */
  3434.  
  3435.     if(ThisFont != PropFont)
  3436.         SetFont(RPort,ThisFont = PropFont);
  3437.  
  3438.         /* Determine lengths of both strings. */
  3439.  
  3440.     LeftLen        = strlen(Left),
  3441.     RightLen    = strlen(Right),
  3442.  
  3443.         /* Determine pixel widths of both strings. */
  3444.  
  3445.     LeftWidth    = TextLength(RPort,(STRPTR)Left,LeftLen);
  3446.     RightWidth    = TextLength(RPort,(STRPTR)Right,RightLen);
  3447.  
  3448.         /* Determine width of the space in between. */
  3449.  
  3450.     Width        = WindowWidth - (LeftWidth + RightWidth + 1);
  3451.  
  3452.         /* Set the status colour. */
  3453.  
  3454.     ConSetColour(COLOUR_STATUS);
  3455.  
  3456.         /* Print the left part if any. */
  3457.  
  3458.     if(LeftLen)
  3459.     {
  3460.         Move(RPort,Window -> BorderLeft,ThisFont -> tf_Baseline + Window -> BorderTop);
  3461.         Text(RPort,(STRPTR)Left,LeftLen);
  3462.     }
  3463.  
  3464.         /* Clear the area between left and right part. */
  3465.  
  3466.     if(Width > 0)
  3467.     {
  3468.         SetAPen(RPort,ConBackPen);
  3469.         RectFill(RPort,LeftWidth + Window -> BorderLeft,Window -> BorderTop,LeftWidth + Width + Window -> BorderLeft,Window -> BorderTop + TextFontHeight - 1);
  3470.         SetAPen(RPort,ConTextPen);
  3471.     }
  3472.  
  3473.         /* Print the right part if any. */
  3474.  
  3475.     if(RightLen)
  3476.     {
  3477.         Move(RPort,Window -> Width - (RightWidth + Window -> BorderRight),Window -> BorderTop + ThisFont -> tf_Baseline);
  3478.         Text(RPort,(STRPTR)Right,RightLen);
  3479.     }
  3480.  
  3481.         /* Return to previous cursor position. */
  3482.  
  3483.     ConSetColour(COLOUR_TEXT);
  3484. }
  3485.  
  3486.     /* ConShowRequest():
  3487.      *
  3488.      *    Display a multiple-choice requester.
  3489.      */
  3490.  
  3491. LONG
  3492. ConShowRequest(const struct Window *Window,const STRPTR Text,const STRPTR Gadgets,...)
  3493. {
  3494.     STATIC struct Requester    BlockRequester;
  3495.  
  3496.     struct EasyStruct    Easy;
  3497.     LONG            Result;
  3498.     ULONG            IDCMP = NULL;
  3499.     va_list            VarArgs;
  3500.  
  3501.         /* Clear the requester and install it, blocking
  3502.          * the parent window.
  3503.          */
  3504.  
  3505.     memset(&BlockRequester,0,sizeof(struct Requester));
  3506.  
  3507.     Request(&BlockRequester,(struct Window *)Window);
  3508.  
  3509.         /* Install the wait mouse pointer. */
  3510.  
  3511.     WaitPointer((struct Window *)Window);
  3512.  
  3513.         /* Fill in the template. */
  3514.  
  3515.     Easy . es_StructSize    = sizeof(struct EasyStruct);
  3516.     Easy . es_Flags        = NULL;
  3517.     Easy . es_Title        = (STRPTR)"Infocom";
  3518.     Easy . es_TextFormat    = (STRPTR)Text;
  3519.     Easy . es_GadgetFormat    = (STRPTR)Gadgets;
  3520.  
  3521.         /* Display the requester. */
  3522.  
  3523.     va_start(VarArgs,Gadgets);
  3524.  
  3525.     Result = EasyRequestArgs((struct Window *)Window,&Easy,&IDCMP,VarArgs);
  3526.  
  3527.     va_end(VarArgs);
  3528.  
  3529.         /* Remove the wait mouse pointer. */
  3530.  
  3531.     ClearPointer((struct Window *)Window);
  3532.  
  3533.         /* Remove the blocking requester. */
  3534.  
  3535.     EndRequest(&BlockRequester,(struct Window *)Window);
  3536.  
  3537.         /* Return the result. */
  3538.  
  3539.     return(Result);
  3540. }
  3541.  
  3542.     /* ConQueryOption(int Option):
  3543.      *
  3544.      *    Query the state of an interpreter option.
  3545.      */
  3546.  
  3547. Bool
  3548. ConQueryOption(int Option)
  3549. {
  3550.     switch(Option)
  3551.     {
  3552.         case OPTION_ATTRIBUTE_ASSIGNMENTS:
  3553.  
  3554.             if(gflags . pr_attr)
  3555.                 return(TRUE);
  3556.             else
  3557.                 break;
  3558.  
  3559.         case OPTION_ATTRIBUTE_TESTS:
  3560.  
  3561.             if(gflags . pr_atest)
  3562.                 return(TRUE);
  3563.             else
  3564.                 break;
  3565.  
  3566.         case OPTION_ECHO:
  3567.  
  3568.             if(gflags . echo)
  3569.                 return(TRUE);
  3570.             else
  3571.                 break;
  3572.  
  3573.         case OPTION_PAGING:
  3574.  
  3575.             if(gflags . paged)
  3576.                 return(TRUE);
  3577.             else
  3578.                 break;
  3579.  
  3580.         case OPTION_PROMPT:
  3581.  
  3582.             if(F1_IS_SET(B_ALT_PROMPT))
  3583.                 return(TRUE);
  3584.             else
  3585.                 break;
  3586.  
  3587.         case OPTION_STATUS:
  3588.  
  3589.             if(gflags . pr_status)
  3590.                 return(TRUE);
  3591.             else
  3592.                 break;
  3593.  
  3594.         case OPTION_TANDY:
  3595.  
  3596.             if(F1_IS_SET(B_TANDY))
  3597.                 return(TRUE);
  3598.             else
  3599.                 break;
  3600.  
  3601.         case OPTION_XFERS:
  3602.  
  3603.             if(gflags . pr_xfers)
  3604.                 return(TRUE);
  3605.             else
  3606.                 break;
  3607.  
  3608.         default:
  3609.  
  3610.             break;
  3611.     }
  3612.  
  3613.     return(FALSE);
  3614. }
  3615.  
  3616.     /* ConUpdateMenus():
  3617.      *
  3618.      *    Update the main menu items corresponding
  3619.      *    to the runtime options.
  3620.      */
  3621.  
  3622. VOID
  3623. ConUpdateMenus()
  3624. {
  3625.     struct MenuItem *Item;
  3626.  
  3627.         /* Block the pull-down menu. */
  3628.  
  3629.     ConLockMenus();
  3630.  
  3631.         /* Are object attribute assignments to be printed? */
  3632.  
  3633.     Item = ItemAddress(Menu,FULLMENUNUM(MENU_OPTIONS,OPTIONSMENU_ATTRIBUTE_ASSIGNMENTS,NOSUB));
  3634.  
  3635.     if(ConQueryOption(OPTION_ATTRIBUTE_ASSIGNMENTS))
  3636.         Item -> Flags |= CHECKED;
  3637.     else
  3638.         Item -> Flags &= ~CHECKED;
  3639.  
  3640.         /* Are object attribute tests to be printed? */
  3641.  
  3642.     Item = ItemAddress(Menu,FULLMENUNUM(MENU_OPTIONS,OPTIONSMENU_ATTRIBUTE_TESTS,NOSUB));
  3643.  
  3644.     if(ConQueryOption(OPTION_ATTRIBUTE_TESTS))
  3645.         Item -> Flags |= CHECKED;
  3646.     else
  3647.         Item -> Flags &= ~CHECKED;
  3648.  
  3649.         /* Is input to be echoed? */
  3650.  
  3651.     Item = ItemAddress(Menu,FULLMENUNUM(MENU_OPTIONS,OPTIONSMENU_ECHO,NOSUB));
  3652.  
  3653.     if(ConQueryOption(OPTION_ECHO))
  3654.         Item -> Flags |= CHECKED;
  3655.     else
  3656.         Item -> Flags &= ~CHECKED;
  3657.  
  3658.         /* Is text paging enabled? */
  3659.  
  3660.     Item = ItemAddress(Menu,FULLMENUNUM(MENU_OPTIONS,OPTIONSMENU_PAGING,NOSUB));
  3661.  
  3662.     if(ConQueryOption(OPTION_PAGING))
  3663.         Item -> Flags |= CHECKED;
  3664.     else
  3665.         Item -> Flags &= ~CHECKED;
  3666.  
  3667.         /* Is the alternate prompt to be displayed? */
  3668.  
  3669.     Item = ItemAddress(Menu,FULLMENUNUM(MENU_OPTIONS,OPTIONSMENU_PROMPT,NOSUB));
  3670.  
  3671.     if(ConQueryOption(OPTION_PROMPT))
  3672.         Item -> Flags |= CHECKED;
  3673.     else
  3674.         Item -> Flags &= ~CHECKED;
  3675.  
  3676.         /* Is the status line to be displayed? */
  3677.  
  3678.     Item = ItemAddress(Menu,FULLMENUNUM(MENU_OPTIONS,OPTIONSMENU_STATUS,NOSUB));
  3679.  
  3680.     if(ConQueryOption(OPTION_STATUS))
  3681.         Item -> Flags |= CHECKED;
  3682.     else
  3683.         Item -> Flags &= ~CHECKED;
  3684.  
  3685.         /* Is the Tandy license to be displayed? */
  3686.  
  3687.     Item = ItemAddress(Menu,FULLMENUNUM(MENU_OPTIONS,OPTIONSMENU_TANDY,NOSUB));
  3688.  
  3689.     if(ConQueryOption(OPTION_TANDY))
  3690.         Item -> Flags |= CHECKED;
  3691.     else
  3692.         Item -> Flags &= ~CHECKED;
  3693.  
  3694.         /* Are object transfers to be displayed? */
  3695.  
  3696.     Item = ItemAddress(Menu,FULLMENUNUM(MENU_OPTIONS,OPTIONSMENU_XFERS,NOSUB));
  3697.  
  3698.     if(ConQueryOption(OPTION_XFERS))
  3699.         Item -> Flags |= CHECKED;
  3700.     else
  3701.         Item -> Flags &= ~CHECKED;
  3702.  
  3703.         /* Enable the pull-down menus again. */
  3704.  
  3705.     ConUnlockMenus();
  3706. }
  3707.  
  3708.     /* ConLockMenus():
  3709.      *
  3710.      *    Lock the menu strip.
  3711.      */
  3712.  
  3713. VOID
  3714. ConLockMenus()
  3715. {
  3716.         /* Are we allowed to do what we want? */
  3717.  
  3718.     if(NewOS)
  3719.     {
  3720.         if(!MenuLockCount++)
  3721.         {
  3722.                 /* Block the menu strip. */
  3723.  
  3724.             Window -> Flags |= WFLG_RMBTRAP;
  3725.         }
  3726.     }
  3727. }
  3728.  
  3729.     /* ConUnlockMenus():
  3730.      *
  3731.      *    Unlock the menu strip.
  3732.      */
  3733.  
  3734. VOID
  3735. ConUnlockMenus()
  3736. {
  3737.         /* Are we allowed to do what we want? */
  3738.  
  3739.     if(NewOS)
  3740.     {
  3741.         if(MenuLockCount > 0)
  3742.         {
  3743.             if(MenuLockCount-- == 1)
  3744.             {
  3745.                     /* Unblock the menu strip. */
  3746.  
  3747.                 Window -> Flags &= ~WFLG_RMBTRAP;
  3748.             }
  3749.         }
  3750.     }
  3751. }
  3752.  
  3753.     /* ConSplitLine(char *Line,int Len,Bool ReturnPrompt):
  3754.      *
  3755.      *    Split a hunk of text into neat little pieces.
  3756.      */
  3757.  
  3758. char *
  3759. ConSplitLine(char *Line,int Len,Bool ReturnPrompt)
  3760. {
  3761.     LONG    Width,
  3762.         Indent,
  3763.         Columns;
  3764.  
  3765.     int    Count,
  3766.         Space;
  3767.  
  3768.         /* Make sure that the rendering area is large enough. */
  3769.  
  3770.     if((WindowWidth - (ConLineIndent * SpaceWidth + ConLineMargin * SpaceWidth)) / TextFontWidth < 40)
  3771.     {
  3772.         do
  3773.         {
  3774.             if(ConLineIndent)
  3775.                 ConLineIndent--;
  3776.  
  3777.             if(ConLineMargin)
  3778.                 ConLineMargin--;
  3779.         }
  3780.         while(ConLineIndent && ConLineMargin && (WindowWidth - (ConLineIndent * SpaceWidth + ConLineMargin * SpaceWidth)) / TextFontWidth < 40);
  3781.     }
  3782.  
  3783.         /* Make sure to leave enough space for the user
  3784.          * to type a character.
  3785.          */
  3786.  
  3787.     if(ReturnPrompt)
  3788.     {
  3789.         Width    = WindowWidth - (2 * TextFontWidth + SpaceWidth * ConLineMargin);
  3790.         Indent    = 0;
  3791.     }
  3792.     else
  3793.     {
  3794.         Width    = WindowWidth - SpaceWidth * (ConLineIndent + ConLineMargin);
  3795.         Indent    = SpaceWidth * ConLineIndent;
  3796.     }
  3797.  
  3798.         /* Determine number of columns. */
  3799.  
  3800.     Columns = (Width - SpaceWidth * (ConLineIndent + ConLineMargin)) / TextFontWidth;
  3801.  
  3802.         /* Process & chop the text. */
  3803.  
  3804.     do
  3805.     {
  3806.             /* Does the entire line fit? */
  3807.  
  3808.         if(Len <= Columns)
  3809.         {
  3810.                 /* Are we to return the
  3811.                  * rest of the line as
  3812.                  * a buffer suitable for
  3813.                  * printing as a prompt?
  3814.                  */
  3815.  
  3816.             if(ReturnPrompt)
  3817.                 return(Line);
  3818.             else
  3819.                 ConPrintLine(Line,Count = Len,Indent);
  3820.         }
  3821.         else
  3822.         {
  3823.                 /* Start with minimum values. */
  3824.  
  3825.             Space = Count = Columns;
  3826.  
  3827.                 /* Try to find the last space in case
  3828.                  * the minimum width is the exact line
  3829.                  * size to fit which would cause the
  3830.                  * line to be broken at the last
  3831.                  * character (generally, not a pretty
  3832.                  * sight at all).
  3833.                  */
  3834.  
  3835.             while(Space > 0 && Line[Space] != ' ')
  3836.                 Space--;
  3837.  
  3838.                 /* Will another character fit? */
  3839.  
  3840.             while(Count < Len && TextLength(RPort,(STRPTR)Line,Count + 1) < Width)
  3841.             {
  3842.                 Count++;
  3843.  
  3844.                     /* Remember last space. */
  3845.  
  3846.                 if(Line[Count] == ' ')
  3847.                     Space = Count;
  3848.             }
  3849.  
  3850.                 /* Print the text. */
  3851.  
  3852.             if(Count == Len)
  3853.             {
  3854.                 if(ReturnPrompt)
  3855.                     return(Line);
  3856.                 else
  3857.                 {
  3858.                     if(Line[Count - 1] == ' ')
  3859.                         ConPrintLine(Line,Count - 1,Indent);
  3860.                     else
  3861.                         ConPrintLine(Line,Count,Indent);
  3862.                 }
  3863.             }
  3864.             else
  3865.             {
  3866.                 if(Line[Count - 1] == ' ')
  3867.                     ConPrintLine(Line,Count - 1,Indent);
  3868.                 else
  3869.                 {
  3870.                     ConPrintLine(Line,Space,Indent);
  3871.  
  3872.                     Count = Space + 1;
  3873.                 }
  3874.             }
  3875.  
  3876.                 /* Move up. */
  3877.  
  3878.             Line += Count;
  3879.         }
  3880.  
  3881.             /* Reduce remaining line length. */
  3882.  
  3883.         Len -= Count;
  3884.     }
  3885.     while(Len > 0);
  3886.  
  3887.         /* Return blank prompt. */
  3888.  
  3889.     return("");
  3890. }
  3891.  
  3892.     /* ConPrintLine(const char *Buffer,int Len,int Indent):
  3893.      *
  3894.      *    Print a line of text.
  3895.      */
  3896.  
  3897. VOID
  3898. ConPrintLine(const char *Buffer,int Len,int Indent)
  3899. {
  3900.         /* Is the plain text window active? */
  3901.  
  3902.     if(!ConOutputWindow)
  3903.     {
  3904.             /* Scroll the screen contents up one line. */
  3905.  
  3906.         ConScrollUp();
  3907.  
  3908.             /* Are we to perform paging? */
  3909.  
  3910.         if(gflags . paged)
  3911.         {
  3912.             int PageLength;
  3913.  
  3914.                 /* Determine current page length. */
  3915.  
  3916.             if(ConNumStatusLines > 1 || gflags . pr_status)
  3917.                 PageLength = ConNumLines - ConNumStatusLines;
  3918.             else
  3919.                 PageLength = ConNumLines;
  3920.  
  3921.                 /* Did we print enough lines already to
  3922.                  * show the `[More]' prompt?
  3923.                  */
  3924.  
  3925.             if(ConLinesPrinted >= PageLength - (ConLineContext + 2))
  3926.             {
  3927.                     /* Turn on the text rendering font. */
  3928.  
  3929.                 if(ThisFont != PropFont)
  3930.                     SetFont(RPort,ThisFont = PropFont);
  3931.  
  3932.                     /* Set special colour. */
  3933.  
  3934.                 ConSetColour(COLOUR_SPECIAL);
  3935.  
  3936.                     /* Show the prompt. */
  3937.  
  3938.                 ConPrintf("[More]");
  3939.  
  3940.                     /* Set text colour. */
  3941.  
  3942.                 ConSetColour(COLOUR_TEXT);
  3943.  
  3944.                     /* Turn on the cursor. */
  3945.  
  3946.                 ConCursorOn(CURSOR_AVERAGE);
  3947.  
  3948.                     /* Block the pull-down menus. */
  3949.  
  3950.                 ConLockMenus();
  3951.  
  3952.                     /* Did the window size change? If so,
  3953.                      * go through the same number of
  3954.                      * actions as in the main input
  3955.                      * routine.
  3956.                      */
  3957.  
  3958.                 while(ConGetChar(TRUE) == TERM_RESIZE)
  3959.                 {
  3960.                     if(Window -> Width != OldWindowWidth)
  3961.                     {
  3962.                             /* Remember new window width. */
  3963.  
  3964.                         OldWindowWidth = Window -> Width;
  3965.  
  3966.                             /* Determine new window dimensions. */
  3967.  
  3968.                         WindowWidth = Window -> Width - (Window -> BorderLeft + Window -> BorderRight);
  3969.  
  3970.                             /* Update score display. */
  3971.  
  3972.                         scr_putscore();
  3973.                     }
  3974.  
  3975.                     if(Window -> Height != OldWindowHeight)
  3976.                     {
  3977.                         WORD Remainder;
  3978.  
  3979.                         ConCursorOff();
  3980.  
  3981.                             /* If the window has become larger than
  3982.                              * before, remove the `[More]' prompt.
  3983.                              */
  3984.  
  3985.                         if(Window -> Height > OldWindowHeight)
  3986.                         {
  3987.                             ConSet(0,TextFontHeight * (ConNumLines - 1),-1);
  3988.  
  3989.                             ConClearEOL();
  3990.                         }
  3991.  
  3992.                             /* Calculate new window dimensions. */
  3993.  
  3994.                         ConNumLines = (Window -> Height - (Window -> BorderTop + Window -> BorderBottom)) / TextFontHeight;
  3995.  
  3996.                         OldWindowHeight = Window -> Height;
  3997.  
  3998.                             /* Set input colour. */
  3999.  
  4000.                         ConSetColour(COLOUR_INPUT);
  4001.  
  4002.                             /* Go to the bottom of the screen. */
  4003.  
  4004.                         ConSet(0,TextFontHeight * (ConNumLines - 1),-1);
  4005.  
  4006.                             /* Show the prompt. */
  4007.  
  4008.                         ConPrintf("[More]");
  4009.  
  4010.                         ConClearEOL();
  4011.  
  4012.                             /* Set text colour. */
  4013.  
  4014.                         ConSetColour(COLOUR_TEXT);
  4015.  
  4016.                             /* Turn on the cursor. */
  4017.  
  4018.                         ConCursorOn(CURSOR_AVERAGE);
  4019.  
  4020.                         if((Remainder = Window -> Height - (Window -> BorderTop + ConNumLines * TextFontHeight + Window -> BorderBottom)) > 0)
  4021.                         {
  4022.                             SetAPen(RPort,ConBackPen);
  4023.                             RectFill(RPort,Window -> BorderLeft,Window -> Height - (Window -> BorderBottom + Remainder),Window -> Width - (Window -> BorderRight + 1),Window -> Height - (Window -> BorderBottom + 1));
  4024.                             SetAPen(RPort,ConTextPen);
  4025.                         }
  4026.                     }
  4027.                 }
  4028.  
  4029.                     /* Enable the pull-down menus again. */
  4030.  
  4031.                 ConUnlockMenus();
  4032.  
  4033.                     /* Erase the `[More]' prompt. */
  4034.  
  4035.                 ConCursorOff();
  4036.  
  4037.                 ConSet(0,TextFontHeight * (ConNumLines - 1),-1);
  4038.  
  4039.                 ConClearEOL();
  4040.  
  4041.                     /* That's all. */
  4042.  
  4043.                 ConLinesPrinted = 0;
  4044.             }
  4045.             else
  4046.                 ConLinesPrinted++;
  4047.         }
  4048.     }
  4049.  
  4050.         /* Is the status window active? */
  4051.  
  4052.     if(ConOutputWindow)
  4053.     {
  4054.             /* Write the string if any. */
  4055.  
  4056.         if(Len)
  4057.         {
  4058.                 /* Are we to change the text rendering font?
  4059.                  * The interpreter may want to change between
  4060.                  * a fixed and a proportional-spaced font.
  4061.                  */
  4062.  
  4063.             if(F2_IS_SET(B_FIXED_FONT))
  4064.             {
  4065.                     /* Use the fixed-width font. */
  4066.  
  4067.                 if(ThisFont != FixedFont)
  4068.                     SetFont(RPort,ThisFont = FixedFont);
  4069.             }
  4070.             else
  4071.             {
  4072.                     /* Use the proportional-spaced font. */
  4073.  
  4074.                 if(ThisFont != PropFont)
  4075.                     SetFont(RPort,ThisFont = PropFont);
  4076.             }
  4077.  
  4078.                 /* Write the string. */
  4079.  
  4080.             ConWrite(Buffer,Len,0);
  4081.         }
  4082.  
  4083.             /* Clear to end of line. */
  4084.  
  4085.         ConClearEOL();
  4086.  
  4087.             /* Update current cursor position. */
  4088.  
  4089.         CursorY    += TextFontHeight;
  4090.         CursorX     = 0;
  4091.     }
  4092.     else
  4093.     {
  4094.             /* Write the string if any. */
  4095.  
  4096.         if(Len)
  4097.         {
  4098.                 /* Are we to change the text rendering font?
  4099.                  * The interpreter may want to change between
  4100.                  * a fixed and a proportional-spaced font.
  4101.                  */
  4102.  
  4103.             if(F2_IS_SET(B_FIXED_FONT))
  4104.             {
  4105.                     /* Use the fixed-width font. */
  4106.  
  4107.                 if(ThisFont != FixedFont)
  4108.                     SetFont(RPort,ThisFont = FixedFont);
  4109.             }
  4110.             else
  4111.             {
  4112.                     /* Use the proportional-spaced font. */
  4113.  
  4114.                 if(ThisFont != PropFont)
  4115.                     SetFont(RPort,ThisFont = PropFont);
  4116.             }
  4117.  
  4118.                 /* Write the string. */
  4119.  
  4120.             ConWrite(Buffer,Len,Indent);
  4121.         }
  4122.     }
  4123. }
  4124.  
  4125.     /* ConCheckStory(char *Name):
  4126.      *
  4127.      *    Check a file to see if it's a valid type 3
  4128.      *    story game file.
  4129.      */
  4130.  
  4131. Bool
  4132. ConCheckStory(const char *Name)
  4133. {
  4134.     struct FileInfoBlock    *FileInfo;
  4135.     Bool             Result = FALSE;
  4136.  
  4137.         /* Allocate space for fileinfo data. */
  4138.  
  4139.     if(FileInfo = (struct FileInfoBlock *)AllocDosObjectTags(DOS_FIB,TAG_DONE))
  4140.     {
  4141.         BPTR FileLock;
  4142.  
  4143.             /* Try to locate the file. */
  4144.  
  4145.         if(FileLock = Lock((STRPTR)Name,ACCESS_READ))
  4146.         {
  4147.                 /* Get a closer look at it. */
  4148.  
  4149.             if(Examine(FileLock,FileInfo))
  4150.             {
  4151.                     /* Does it look like a valid file? */
  4152.  
  4153.                 if(FileInfo -> fib_DirEntryType < 0 && FileInfo -> fib_Size > 0)
  4154.                 {
  4155.                     FILE *StoryFile;
  4156.  
  4157.                         /* Try to open the file for reading. */
  4158.  
  4159.                     if(StoryFile = fopen(Name,"rb"))
  4160.                     {
  4161.                             /* Does it look like a type 3
  4162.                              * story game file?
  4163.                              */
  4164.  
  4165.                         if(fgetc(StoryFile) == 3)
  4166.                             Result = TRUE;
  4167.  
  4168.                             /* Close the file. */
  4169.  
  4170.                         fclose(StoryFile);
  4171.                     }
  4172.                 }
  4173.             }
  4174.  
  4175.                 /* Release the file lock. */
  4176.  
  4177.             UnLock(FileLock);
  4178.         }
  4179.  
  4180.             /* Free fileinfo data. */
  4181.  
  4182.         FreeDosObject(DOS_FIB,FileInfo);
  4183.     }
  4184.  
  4185.     return(Result);
  4186. }
  4187.  
  4188.     /* ConLocateStory(char *Directory,char *Default):
  4189.      *
  4190.      *    Try to locate a story file in a directory.
  4191.      */
  4192.  
  4193. char *
  4194. ConLocateStory(const char *Directory,const char *Default)
  4195. {
  4196.     char     LocalBuffer[MAX_FILENAME_LENGTH];
  4197.     int     i,j;
  4198.  
  4199.         /* Start with the current default name. */
  4200.  
  4201.     if(Default[0])
  4202.     {
  4203.         for(j = 0 ; StoryExtensions[j] ; j++)
  4204.         {
  4205.                 /* Copy the directory name. */
  4206.  
  4207.             strcpy(TempBuffer,Directory);
  4208.  
  4209.                 /* Build the story file name. */
  4210.  
  4211.             strcpy(LocalBuffer,Default);
  4212.             strcat(LocalBuffer,StoryExtensions[j]);
  4213.  
  4214.                 /* Build the full path name. */
  4215.  
  4216.             if(AddPart(TempBuffer,LocalBuffer,MAX_FILENAME_LENGTH))
  4217.             {
  4218.                     /* Is it a valid story game file? */
  4219.  
  4220.                 if(ConCheckStory(TempBuffer))
  4221.                     return((char *)TempBuffer);
  4222.             }
  4223.         }
  4224.     }
  4225.  
  4226.         /* Run down the number of alternatives. */
  4227.  
  4228.     for(i = 0 ; StoryNames[i] ; i++)
  4229.     {
  4230.             /* Run down the number of file name extensions. */
  4231.  
  4232.         for(j = 0 ; StoryExtensions[j] ; j++)
  4233.         {
  4234.                 /* Copy the directory name. */
  4235.  
  4236.             strcpy(TempBuffer,Directory);
  4237.  
  4238.                 /* Build the story file name. */
  4239.  
  4240.             strcpy(LocalBuffer,StoryNames[i]);
  4241.             strcat(LocalBuffer,StoryExtensions[j]);
  4242.  
  4243.                 /* Build the full path name. */
  4244.  
  4245.             if(AddPart(TempBuffer,LocalBuffer,MAX_FILENAME_LENGTH))
  4246.             {
  4247.                     /* Is it a valid story game file? */
  4248.  
  4249.                 if(ConCheckStory(TempBuffer))
  4250.                     return((char *)TempBuffer);
  4251.             }
  4252.         }
  4253.     }
  4254.  
  4255.     return(NULL);
  4256. }
  4257.  
  4258.     /* ConQueryStoryInformation(const char *Name):
  4259.      *
  4260.      *    Query the story game header for information.
  4261.      */
  4262.  
  4263. VOID
  4264. ConQueryStoryInformation(const char *Name)
  4265. {
  4266.     FILE *GameFile;
  4267.  
  4268.         /* Reset information. */
  4269.  
  4270.     StorySerial = StoryRelease = 0;
  4271.  
  4272.         /* Try to open the file for reading. */
  4273.  
  4274.     if(GameFile = fopen(Name,"rb"))
  4275.     {
  4276.         header_t GameHeader;
  4277.  
  4278.             /* Read the game file header. */
  4279.  
  4280.         if(fread(&GameHeader,sizeof(header_t),1,GameFile) == 1)
  4281.         {
  4282.                 /* Is it a type 3 game? */
  4283.  
  4284.             if(GameHeader . z_version == 3)
  4285.             {
  4286.                 int    Serial = 0,
  4287.                     i;
  4288.  
  4289.                     /* Calculate the serial number. */
  4290.  
  4291.                 for(i = 0 ; i < 6 ; i++)
  4292.                 {
  4293.                     Serial *= 10;
  4294.                     Serial += GameHeader . serial_no[i] - '0';
  4295.                 }
  4296.  
  4297.                     /* Try to find a corresponding
  4298.                      * game in the list.
  4299.                      */
  4300.  
  4301.                 for(i = 0 ; SerialNumbers[i][SERIAL_INDEX] != -1 ; i++)
  4302.                 {
  4303.                         /* Do the serial and release numbers match? */
  4304.  
  4305.                     if(Serial == SerialNumbers[i][SERIAL_NUMBER] && GameHeader . release == SerialNumbers[i][SERIAL_RELEASE])
  4306.                     {
  4307.                         StorySerial    = Serial;
  4308.                         StoryRelease    = GameHeader . release;
  4309.                         StoryIndex    = SerialNumbers[i][SERIAL_INDEX];
  4310.                     }
  4311.                 }
  4312.             }
  4313.         }
  4314.  
  4315.             /* Close the story file. */
  4316.  
  4317.         fclose(GameFile);
  4318.     }
  4319. }
  4320.  
  4321.     /* ConAbout():
  4322.      *
  4323.      *    Display an information requester.
  4324.      */
  4325.  
  4326. VOID
  4327. ConAbout()
  4328. {
  4329.         /* Show the information requester. */
  4330.  
  4331.     if(StorySerial)
  4332.     {
  4333.         ConShowRequest(Window,"\"%s\" (%s)\nRelease %ld / Serial number %ld\nWritten by %s\n\n\"pinfo\" version %ld.%ld, Amiga release %ld.%ld\nCopyright \251 1987-1992 InfoTaskForce",
  4334.             "Continue",Titles[StoryIndex],Levels[GameLevels[StoryIndex]],StoryRelease,StorySerial,Authors[StoryIndex],VERSION,PATCHLEVEL,AMIGA_VERSION,AMIGA_REVISION);
  4335.     }
  4336.     else
  4337.     {
  4338.         ConShowRequest(Window,"\"pinfo\" version %ld.%ld, Amiga release %ld.%ld\nCopyright \251 1987-1992 InfoTaskForce",
  4339.             "Continue",VERSION,PATCHLEVEL,AMIGA_VERSION,AMIGA_REVISION);
  4340.     }
  4341. }
  4342.